1. EventLoop
EventLoop是一个程序结构,用于等待和发送消息和事件。简单说,就是在程序中设置两个线程:一个负责程序本身的运行,称为"主线程";另一个负责主线程与其他进程(主要是各种I/O操作)的通信,被称为"Event Loop线程"(可以译为"消息线程")。
大体解释一下NodeJS的Event Loop过程:
- 执行全局Script的同步代码
- 执行microtask微任务,先执行所有Next Tick Queue中的所有任务,再执行Other Microtask Queue中的所有任务
- 开始执行macrotask宏任务,共6个阶段,从第1个阶段开始执行相应每一个阶段macrotask中的所有任务,注意,这里是所有每个阶段宏任务队列的所有任务,在浏览器的Event Loop中是只取宏队列的第一个任务出来执行,每一个阶段的macrotask任务执行完毕后,开始执行微任务,也就是步骤2
1.1 宏队列
宏队列,macrotask,也叫tasks。 一些异步任务的回调会依次进入macro task queue,等待后续被调用,这些异步任务包括:
- setTimeout
- setInterval
- setImmediate (Node独有)
- requestAnimationFrame (浏览器独有)
- I/O
- UI rendering (浏览器独有)
NodeJS的Event Loop中,执行宏队列的回调任务有6个阶段,如下图:
各个阶段执行的任务如下:
- timers阶段:这个阶段执行setTimeout和setInterval预定的callback
- I/O callback阶段:执行除了close事件的callbacks、被timers设定的callbacks、setImmediate()设定的callbacks这些之外的callbacks
- idle, prepare阶段:仅node内部使用
- poll阶段:获取新的I/O事件,适当的条件下node将阻塞在这里
- check阶段:执行setImmediate()设定的callbacks
- close callbacks阶段:执行socket.on('close', ....)这些callbacks
NodeJS中宏队列主要有4个
- Timers Queue
- IO Callbacks Queue
- Check Queue
- Close Callbacks Queue 这4个都属于宏队列,但是在浏览器中,可以认为只有一个宏队列,所有的macrotask都会被加到这一个宏队列中,但是在NodeJS中,不同的macrotask会被放置在不同的宏队列中。
1.2 微队列
微队列,microtask,也叫jobs。 另一些异步任务的回调会依次进入micro task queue,等待后续被调用,这些异步任务包括:
- process.nextTick (Node独有)
- Promise
- Object.observe
- MutationObserver
NodeJS中微队列主要有2个:
- Next Tick Queue:是放置process.nextTick(callback)的回调任务的
- Other Micro Queue:放置其他microtask,比如Promise等 在浏览器中,也可以认为只有一个微队列,所有的microtask都会被加到这一个微队列中,但是在NodeJS中,不同的microtask会被放置在不同的微队列中。
1.3 举例
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve(
console.log('Promise')
).then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
输出结果:
script start
Promise
script end
promise1
promise2
setTimeout