前言
本文仅以记录浏览器环境的event loop 和 node环境中的event loop的了解过程,如果错误,欢迎指正
浏览器环境
Event Loop是指在js执行环境中存在主执行线程和任务队列(Task Queue),其中所有同步任务都在主执行线程中形成一个执行栈,所有异步任务都会放到任务队列中
具体执行过程:
1. 主线程执行同步任务, 在主线程执行的过程中,不断行程堆栈并执行出栈入栈的操作
2. 如果主线程任务没有完成,继续完成,如果完成了就执行下一步
3. 系统读取队列任务, 开始执行
4. 不断循环
而我们的异步任务中,分为宏任务(macrotask) 和微任务(microtask),
执行顺序
1. 先取出macrotask任务队列中的第一个任务进行执行
2. 取出Macrotask Queue中一个任务执行。
3. 取出Microtask Queue中任务执行直到清空。
node
执行任务为:
1. timers 阶段: 这个阶段执行setTimeout和setInterval预定的callback;
2. I/O callbacks 阶段: 执行除了 close事件的callbacks、被timers设定的callbacks、setImmediate()设定的callbacks这些之外的callbacks;
3. idle, prepare 阶段: 仅node内部使用;
4. poll 阶段: 获取新的I/O事件, 适当的条件下node将阻塞在这里;
5. check 阶段: 执行setImmediate() 设定的callbacks;
6. close callbacks 阶段: 执行socket.on('close', ...)这些 callback
参考文档,对比 setImmediate 和 process.nextTick()
setImmediate 和 process.nextTick()setImmediate(() => console.log('immediate1'));setImmediate(() => console.log('immediate2'));setTimeout(() => console.log('setTimeout1'), 1000);setTimeout(() => { console.log('setTimeout2'); process.nextTick(() => console.log('nextTick1'));}, 0);setTimeout(() => console.log('setTimeout3'), 0);process.nextTick(() => console.log('nextTick2'));process.nextTick(() => { process.nextTick(console.log.bind(console, 'nextTick3'));});process.nextTick(() => console.log('nextTick4'));复制代码
执行结果:
在控制台中执行node index.js,得到的结果如下:
nextTick2nextTick4nextTick3setTimeout2setTimeout3nextTick1immediate1immediate2setTimeout1复制代码
结论
在node中,nextTick的优先级高于setTimeout和setImmediate(),所以会先执行nextTick里面的信息打印。
但是对于嵌套的nextTick,会慢于同步的nextTick,所以nextTick4会先于nextTick3
然后开始一个Event Loop过程,首先执行timer阶段,而此时setTimeout所需要等待的时间是0,所以立即执行setTimeout2和setTimeout3里面的逻辑。而setTimeout1由于设置了执行时间,不满足执行条件,被放到下一轮Event Loop
当前Event Loop执行到check阶段,于是打印出immediate1、immediate2
执行后面的Event Loop,当setTimeout1达到执行条件时执行
基于node事件的event loop,我们使用事件也变得方便快捷
event.emit('eventType', () => {})
event.on('eventType', () => {})