浅探EventLoop事件循环机制

何为Event Loop

event loop是一个执行模型,是js异步运行的核心。js是一门单线程的语言,意味着js无法进行多线程操作,但是js中的异步功能可以完全模拟多线程。

宏队列 macrotask

一些异步任务的回调会依次进入macro task queue,等待后续被调用,这些异步任务包括

  • setTimeout
  • setInterval
  • requestAnimationFrame (浏览器独有)
  • I/O
  • UI rendering (浏览器独有)

微队列,microtask

一些异步任务的回调会依次进入micro task queue,等待后续被调用,这些异步任务包括:

  • process.nextTick (Node独有)
  • Promise
  • Object.observe
  • MutationObserver
  • Event Loop执行机制
这张图将浏览器的Event Loop完整的描述了出来,以下是javascript执行代码的具体顺序
  1. 执行全局Script同步代码
  2. 全局Script代码执行完毕后,调用栈Stack会清空;
  3. 微队列中取出位于队首的回调任务,放入调用栈Stack中执行,执行完后microtask queue长度减1;
  4. 继续取出位于队首的任务,放入调用栈Stack中执行,以此类推,直到把microtask queue中的所有任务都执行完毕。如果在执行microtask的过程中,又产生了microtask,那么会加入到队列的末尾,也会在这个周期被调用执行;
  5. microtask queue中的所有任务都执行完毕,此时microtask queue为空队列,调用栈Stack也为空;
  6. 取出宏队列macrotask queue中位于队首的任务,放入Stack中执行; 执行完毕后,调用栈Stack为空;
  7. 重复第3-6个步骤;

要点

由此归纳出两个要点:

  1. 宏队列macrotask一次只从队列中取一个任务执行,执行完后就去执行微任务队列中的任务;
  2. 微任务队列中所有的任务都会被依次取出来执行,直到微任务队列为空;

接下来是一个代码实例

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);
复制代码

输出结果:1 4 7 5 2 3 6 整个流程为:

  1. 执行全局同步代码(promise中在resolve或reject前的也算) 所以输出1,4,7
  2. 执行微队列代码 此时的微队列中的任务为Promise中的resolve(5)则输出5
  3. 执行宏队列中的队首任务(注意只执行一个宏任务),此时的队首任务为代码中第一个setTimeOut,则输出了2。在执行这个任务时又产生了一个新的微任务。
  4. 执行新产生的微队列中的任务,所以输出了3
  5. 微任务队列为空,宏队列中还有一个任务,于是输出6
全部评论

相关推荐

10-11 17:30
湖南大学 C++
我已成为0offer的糕手:羡慕
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务