加载事件

当界面结束装载时,会触发窗口对象和文档body对象的"load"事件。该事件通常用于在当整个文档构建完成时,进行初始化。请记住<script>标签的内容是一遇到就执行的。这可能太早了,比如有时脚本需要处理在<script>标签后出现的内容。

诸如imagescript这类会装载外部文件的标签都有load事件,指示其引用文件装载完毕。类似于焦点事件,装载事件是不会传播的。

当页面关闭或跳转(比如跳转到一个链接)时,会触发beforeunload事件。该事件用于防止用户突然关闭文档而丢失工作结果。你无法使用preventDefault方法阻止页面卸载。它通过从处理器返回非空值来完成。当你这样做时,浏览器会通过显示一个对话框,询问用户是否关闭页面的对话框中。该机制确保用户可以离开,即使在那些想要留住用户,强制用户看广告的恶意页面上,也是这样。

事件和事件循环

在事件循环的上下文中,如第 11 章中所述,浏览器事件处理器的行为,类似于其他异步通知。 它们是在事件发生时调度的,但在它们有机会运行之前,必须等待其他正在运行的脚本完成。

仅当没有别的事情正在运行时,才能处理事件,这个事实意味着,如果事件循环与其他工作捆绑在一起,任何页面交互(通过事件发生)都将延迟,直到有时间处理它为止。 因此,如果您安排了太多工作,无论是长时间运行的事件处理器还是大量短时间运行的工作,该页面都会变得缓慢且麻烦。

如果您想在背后做一些耗时的事情而不会冻结页面,浏览器会提供一些名为 Web Worker 的东西。 Web Worker 是一个 JavaScript 过程,与主脚本一起在自己的时间线上运行。

想象一下,计算一个数字的平方运算是一个重量级的,长期运行的计算,我们希望在一个单独的线程中执行。 我们可以编写一个名为code/squareworker.js的文件,通过计算平方并发回消息来响应消息:

  1. addEventListener("message", event => {
  2. postMessage(event.data * event.data);
  3. });

为了避免多线程触及相同数据的问题,Web Worker 不会将其全局作用域或任何其他数据与主脚本的环境共享。 相反,你必须通过来回发送消息与他们沟通。

此代码会生成一个运行该脚本的 Web Worker,向其发送几条消息并输出响应。

  1. let squareWorker = new Worker("code/squareworker.js");
  2. squareWorker.addEventListener("message", event => {
  3. console.log("The worker responded:", event.data);
  4. });
  5. squareWorker.postMessage(10);
  6. squareWorker.postMessage(24);

函数postMessage会发送一条消息,触发接收方的message事件。创建工作单元的脚本通过Worker对象收发消息,而worker则直接向其全局作用域发送消息,或监听其消息。只有可以表示为 JSON 的值可以作为消息发送 - 另一方将接收它们的副本,而不是值本身。