返回

揭秘 JavaScript 事件循环的秘密:宏任务与微任务

前端

在 JavaScript 的世界里,事件循环扮演着至关重要的角色,负责管理代码的执行顺序。它是一个单线程机制,一次只执行一个任务。然而,通过巧妙地利用宏任务和微任务,JavaScript 能够异步处理事件,从而创建响应迅速、高效的 Web 应用程序。

事件循环的概念

事件循环是一种循环机制,它不断检查是否存在等待执行的任务。当发现任务时,事件循环会将其从任务队列中取出并执行。任务队列是一个先进先出 (FIFO) 队列,这意味着最早添加的任务将首先被执行。

宏任务

宏任务是指需要较长时间才能完成的任务,例如 DOM 操作、网络请求和 setTimeout()。当事件循环发现宏任务时,它会将其添加到宏任务队列中。宏任务队列是另一个先进先出队列,这意味着宏任务将按照添加顺序依次执行。

微任务

微任务是指需要在当前事件循环中执行的任务,例如 Promise.then() 和 MutationObserver。当事件循环发现微任务时,它会将其添加到微任务队列中。微任务队列在每个宏任务执行完毕后被检查,这意味着微任务将在所有宏任务执行完毕后执行。

执行顺序

事件循环的执行顺序如下:

  1. 执行同步代码: 首先,事件循环将执行同步代码,即主线程中的所有代码。
  2. 执行微任务: 同步代码执行完毕后,事件循环将检查微任务队列并执行所有微任务。
  3. 执行宏任务: 微任务执行完毕后,事件循环将检查宏任务队列并执行所有宏任务。
  4. 检查事件队列: 宏任务执行完毕后,事件循环将检查事件队列,该队列包含来自外部事件(如鼠标点击或网络请求)的任务。如果有事件,事件循环将触发事件处理程序,并将其添加到任务队列中。
  5. 重复: 事件循环不断重复此过程,直到任务队列和事件队列都为空。

示例

让我们通过几个示例来理解事件循环的执行流程:

示例 1:

console.log("同步代码 1");

setTimeout(() => {
  console.log("宏任务");
}, 0);

Promise.resolve().then(() => {
  console.log("微任务");
});

console.log("同步代码 2");

执行顺序:

  1. 同步代码 1
  2. 同步代码 2
  3. 微任务
  4. 宏任务

示例 2:

console.log("同步代码 1");

setTimeout(() => {
  console.log("宏任务 1");
  setTimeout(() => {
    console.log("宏任务 2");
  }, 0);
}, 0);

Promise.resolve().then(() => {
  console.log("微任务 1");
  Promise.resolve().then(() => {
    console.log("微任务 2");
  });
});

console.log("同步代码 2");

执行顺序:

  1. 同步代码 1
  2. 同步代码 2
  3. 微任务 1
  4. 微任务 2
  5. 宏任务 1
  6. 宏任务 2

结论

JavaScript 的事件循环是一个强大的机制,它使我们能够在单线程环境中异步处理事件。通过理解宏任务和微任务的概念,我们可以优化我们的代码,创建响应迅速且高效的 Web 应用程序。掌握事件循环是任何 JavaScript 开发人员必备的技能。