Skip to the content.

Event Loop

Event Loop 是一个执行模型,浏览器和 NodeJS 基于不同的技术实现了各自的 Event Loop



宏队列和微队列

宏队列 mcacrotask 也叫 tasks。一些异步任务的回调会依次进入 macro task queue,等待后续被调用


微队列 microtask 也叫 jobs。另一些异步任务的回调以此进入 micro task queue,等待后续被调用

浏览器的 Event Loop

执行 Javascript 的具体流程

  1. 执行全局 Script 同步代码,这些同步代码有一些是同步语句,有一些是异步语句
  2. 全局 Script 代码执行完毕后,调用栈 Stack 会清空
  3. 微队列(microtask queue)列去除位于队首的任务,放入调用栈 Stack 中执行,执行完毕后微队列长度减 1
  4. 如果在执行微队列过程中,又产生了新任务,则该任务放入队列的队尾。
  5. 微队列中所有任务都执行完毕,此时微队列为空,调用栈 Stack 也为空
  6. 取出宏队列(macrotask queue)中位于队首的任务,放入 Stack 中执行
  7. 执行完成后,调用栈 Stack 为空
  8. 重复 3 ~ 7 步骤

三个重点

习题练习

console.log(1);

setTimeout(() => {
  console.log(2);
  Promise.resolve().then(() => {
    console.log(3);
  });
});

new Promise((resolve, reject) => {
  console.log(4);
  resolve(5);
}).then((data) => {
  console.log(data);
});

setTimeout(() => {
  console.log(6);
});

console.log(7);

执行过程

Step 1

  console.log(1)

Step 2

setTimeout(() => {
  // 这个回调函数叫做callback1,setTimeout属于macrotask,所以放到macrotask queue中
  console.log(2);
  Promise.resolve().then(() => {
    console.log(3);
  });
});

Step 3

new Promise((resolve, reject) => {
  // 注意,这里是同步执行的,如果不太清楚,可以去看一下promise的实现
  console.log(4);
  resolve(5);
}).then((data) => {
  // 这个回调函数叫做callback2,promise属于microtask,所以放到microtask queue中
  console.log(data);
});

Step 4

setTimeout(() => {
  // 这个回调函数叫做callback3,setTimeout属于macrotask,所以放到macrotask queue中
  console.log(6);
});

Step 5

console.log(7);

全局的 Script 代码已执行完毕,进入下一个步骤,从微队列中依次取出任务执行,直到微队列为空


Step 6

console.log(data); // 这里data是Promise的决议值5

微队列中所有任务执行完毕,开始从宏队列中执行队首任务


Step 7

console.log(2);

执行 callback1 时遇到了另一个 Promise,Promise 执行完后在微队列中注册了一个 callback4 回调函数


Step 8

Promise.resolve().then(() => {
  // 这个回调函数叫做callback4,promise属于微队列
  console.log(3);
});

执行完一个宏任务后,会再去执行微队列中的所有任务


Step 9

console.log(3);

微队列执行完成后,会再去执行队首的宏任务


Step 10

console.log(6);

至此所有队列都已清空,最终打印结果为 1 4 7 5 2 3 6

再来一个例子

console.log(1);

setTimeout(() => {
  console.log(2);
  Promise.resolve().then(() => {
    console.log(3);
  });
});

new Promise((resolve, reject) => {
  console.log(4);
  resolve(5);
}).then((data) => {
  console.log(data);

  Promise.resolve()
    .then(() => {
      console.log(6);
    })
    .then(() => {
      console.log(7);

      setTimeout(() => {
        console.log(8);
      }, 0);
    });
});

setTimeout(() => {
  console.log(9);
});

console.log(10);

答案是:

1 4 10 5 6 7 2 3 9 8

加载过程可视化

参见