博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Event Loop详解
阅读量:6785 次
发布时间:2019-06-26

本文共 2348 字,大约阅读时间需要 7 分钟。

浏览器Event Loop执行流程

事件循环其实就是入栈出栈的循环。上面例子中说到了setTimeout,那setInterval呢,Promise呢等等等等,有很多异步的函数。但是这些异步任务有分宏任务(macro-task)和微任务(micro-task): macro-task包括: setTimeout, setInterval, setImmediate, I/O, UI rendering。 micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver。 每一次Event Loop触发时:

  1. 执行完主执行线程中的任务。
  2. 取出micro-task中任务执行直到清空。
  3. 取出macro-task中一个任务执行。
  4. 取出micro-task中任务执行直到清空。
  5. 重复3和4。

Node Event Loop执行流程

js执行为单线程,所有代码皆在主线程调用栈完成执行。当主线程任务清空后才会去轮询取任务队列中任务。

循环阶段

在node中事件每一轮循环按照顺序分为6个阶段,来自libuv的实现:

  1. timers:执行满足条件的setTimeout、setInterval回调。
  2. I/O callbacks:是否有已完成的I/O操作的回调函数,来自上一轮的poll残留。
  3. idle,prepare:可忽略
  4. poll:等待还没完成的I/O事件,会因timers和超时时间等结束等待。
  5. check:执行setImmediate的回调。
  6. close callbacks:关闭所有的closing handles,一些onclose事件。

几个队列

除上述循环阶段中的任务类型,我们还剩下浏览器和node共有的microtask和node独有的process.nextTick,我们称之为Microtask Queue和NextTick Queue。

我们把循环中的几个阶段的执行队列也分别称为Timers Queue、I/O Queue、Check Queue、Close Queue。

循环之前

在进入第一次循环之前,会先进行如下操作:

  • 同步任务
  • 发出异步请求
  • 规划定时器生效的时间
  • 执行process.nextTick()

开始循环

按照我们的循环的6个阶段依次执行,每次拿出当前阶段中的全部任务执行,清空NextTick Queue,清空Microtask Queue。再执行下一阶段,全部6个阶段执行完毕后,进入下轮循环。即:

  • 清空当前循环内的Timers Queue,清空NextTick Queue,清空Microtask Queue。
  • 清空当前循环内的I/O Queue,清空NextTick Queue,清空Microtask Queue。
  • 清空当前循环内的Check Queu,清空NextTick Queue,清空Microtask Queue。
  • 清空当前循环内的Close Queu,清空NextTick Queue,清空Microtask Queue。
  • 进入下轮循环。

可以看出,nextTick优先级比promise等microtask高。setTimeoutsetInterval优先级比setImmediate高。

注意

  • 如果在timers阶段执行时创建了setImmediate则会在此轮循环的check阶段执行,如果在timers阶段创建了setTimeout,由于timers已取出完毕,则会进入下轮循环,check阶段创建timers任务同理。
  • setTimeout优先级比setImmediate高,但是由于setTimeout(fn,0)的真正延迟不可能完全为0秒,可能出现先创建的setTimeout(fn,0)而比setImmediate的回调后执行的情况。

伪代码

while (true) {  loop.forEach((阶段) => {    阶段全部任务()    nextTick全部任务()    microTask全部任务()  })  loop = loop.next}复制代码

实际例子

setImmediate(function(){    console.log(1);},0);setTimeout(function(){    console.log(2);},0);new Promise(function(resolve){    console.log(3);    resolve();    console.log(4);}).then(function(){    console.log(5);});console.log(6);process.nextTick(function(){    console.log(7);});console.log(8);复制代码
结果是:3 4 6 8 7 5 2 1复制代码

优先级关系如下:

process.nextTick > promise.then > setTimeout > setImmediate复制代码

V8实现中,两个队列各包含不同的任务:

macrotasks: script(整体代码),setTimeout, setInterval, setImmediate, I/O, UI renderingmicrotasks: process.nextTick, Promises, Object.observe, MutationObserver复制代码

参考

  1. https://juejin.im/post/5aa5dcabf265da239c7afe1e

转载地址:http://audgo.baihongyu.com/

你可能感兴趣的文章
Docker 命令行和后台参数
查看>>
英雄王座的数据库表格部分成功转换
查看>>
AbstractQueuedSynchronizer的介绍和原理分析
查看>>
python socket 原汁原味代码
查看>>
Kubernetes的service mesh——第一部分:Service的重要指标
查看>>
全链路监控
查看>>
我的友情链接
查看>>
我的IT博客之路
查看>>
深入理解javascript原型和闭包(10)——this
查看>>
系统集成资质培训-论文写作-几个题目如何写?(updated)
查看>>
搭建自己的框架之1:Rxjava2+Retrofit2 实现Android Http请求
查看>>
排序算法-快速排序
查看>>
CSS3 Background 属性介绍
查看>>
frameset 的一些小应用
查看>>
eclipse自动换行
查看>>
Android PDF 阅读器源码
查看>>
我的友情链接
查看>>
silverlight渐隐效果
查看>>
使用Docker实现php代码在线测试执行工具-toolfk.com
查看>>
簡單範例 mergecap,wireshark 付屬程式
查看>>