✊不积跬步,无以至千里;不积小流,无以成江海
EventLoop 是什么?
Node.js 将各种函数(也叫任务或回调【即通过nodejs向操作系统发出各种请求,由操作系统给出回应】)分成至少 6 类,按先后顺序调用,因此将时间分为六个阶段:
-
timers 阶段(setTimeout)
-
I/O callbacks 该阶段不用管
-
idle, prepare 该阶段不用管
-
poll 轮询阶段【类似于问操作系统我的请求到了没】,停留时间最长,可以随时离开。
a. 主要用来处理 I/O 事件,该阶段中 Node 会不停询问操作系统有没有文件数据、网络数据等
b. 如果 Node 发现有 timer 快到时间了或者有 setImmediate 任务,就会主动离开 poll 阶段
-
check 阶段,主要处理 setImmediate 任务
-
close callback 该阶段不用管
Node.js 会不停的从 1 到 6 循环处理各种事件,这个过程叫做事件循环(EventLoop)。
javascript是单线程,所以只有唯一的事件循环,这个时候js就把所有任务分为了两种:同步任务和异步任务。
而异步任务的两种分类分别为:宏任务和微任务。事件的执行顺序是先执行微任务,然后执行宏任务。微任务按先进先出的顺序执行;微任务清空后再执行宏任务,按先进先出的顺序取出执行。
nextTick
process.nextTick(fn) 的 fn 会在什么时候执行呢?
在 Node.js 11 之前,会在每个阶段的末尾集中执行(俗称队尾执行)。
在 Node.js 11 之后,会在每个阶段的任务间隙执行(俗称插队执行)。
浏览器跟 Node.js 11 之后的情况类似。可以用 window.queueMicrotask 模拟nextTick。
Promise
Promise.resolve(1).then(fn) 的 fn 会在什么时候执行?
这要看 Promise 源码是如何实现的,一般都是用 process.nextTick(fn) 实现的,所以直接参考 nextTick。
async / await
这是 Promise 的语法糖,所以直接转为 Promise 写法即可。
总结
async/await参考了promise,promise参考了nextTick,nextTick参考了queueMicrotask。所以其实本质都是一个东西
例子
其实结果是D。因为存在谁先启动不确定的情况,所以有可能nodejs停留在poll阶段的时候反而才开始setTImeOut,这种情况就会先执行SetImmediate,导致先setIm再setT。剩下就是按顺序执行了。
await async2()
console.log('2')
}
被改写为了
async2().then(()=>{console.log('2')})
帮助判断
- 首先async函数都先放到后面去看。
- 第一个执行的就是cl 4
- 之后再setTimeout任务中写入5
- 之后执行async1
- 进入async1后 cl 1
- 由于await cl 2,所以把cl 2 放到nextTick里面
- 再直接到async2
- 进入async2后 cl 3
- 这里async1执行完了,回到new promise,由于new promise里面的函数是立刻执行的
- 所以进入new promise后cl 6
- 由于有.then所以把cl 7也放入到nextTick里面
- 之后执行cl 8
- 然后由于是node11之后的,存在插队机制,所以先执行插队内容,即nextTick的内容
- 再最后执行setTimeout的内容
所以结果为 41368275