Web 浏览器中的事件循环

绝大多数现代 JavaScript 环境都根据事件循环工作。这是计算机编程中的一个常见概念,这实际上意味着你的程序不断地等待新事物发生,并且当它们发生时,会对它们做出反应。在主机环境调用到你的程序,在产卵事件循环,然后一个任务 运行完成。当转弯完成后,主机环境会在所有这一切开始之前等待其他事情发生。

一个简单的例子就是在浏览器中。请考虑以下示例:

<!DOCTYPE html>
<title>Event loop example</title>

<script>
console.log("this a script entry point");

document.body.onclick = () => {
  console.log("onclick");
};

setTimeout(() => {
  console.log("setTimeout callback log 1");
  console.log("setTimeout callback log 2");
}, 100);
</script>

在此示例中,主机环境是 Web 浏览器。

  1. HTML 解析器将首先执行 <script>。它将运行完成。
  2. setTimeout 的调用告诉浏览器,在 100 毫秒之后,它应该将任务排队以执行给定的操作。
  3. 与此同时,事件循环负责不断检查是否还有其他事情要做:例如,渲染网页。
  4. 在 100 毫秒之后,如果事件循环由于某些其他原因而不忙,它将看到 setTimeout 排队的任务,并运行该函数,记录这两个语句。
  5. 在任何时候,如果有人点击了正文,浏览器会将任务发布到事件循环以运行点击处理函数。事件循环,因为它不断检查要做什么,将看到这一点,并运行该功能。

你可以看到在此示例中,如何在 JavaScript 代码中有几种不同类型的入口点,事件循环调用它们:

  • <script> 元素立即被调用
  • setTimeout 任务将发布到事件循环并运行一次
  • 点击处理程序任务可以多次发布并每次运行

事件循环的每一轮都有很多东西; 只有部分人会调用这些 JavaScript 任务。有关完整详细信息,请参阅 HTML 规范

最后一件事:我们说每个事件循环任务运行完成是什么意思?我们的意思是通常不可能中断排队等待作为任务运行的代码块,并且永远不可能运行与另一个代码块交错的代码。例如,即使你在完美时间点击,也无法获得上述代码来记录两个 setTimeout callback log 1/2" 之间的 onclick。这是由于任务发布的工作方式; 它是合作的和基于队列的,而不是先发制人的。