NodeJS 系统
- 通过事件循环机制运行 JS 代码
- 提供线程池处理 I/O 操作任务
- 两种线程:
- 事件循环线程:负责任务安排
(require,同步执行回调、注册新任务) - 线程池(libuv 实现):负责处理任务
(I/O 操作、CPU 密集型任务)
- 事件循环线程:负责任务安排
事件队列实际上不存在维护事件队列的东西出现,当拿到事件时就住相应 API 线程池中扔。
Node 事件环
Node 事件环 与 浏览器事件环不一样,
浏览器事件环可以明显感觉为一个环型
但对于 NodeJS 并不是一个真正的环,是把不同的任务分配至不同的阶段,然后阶段从上往下地重复执行,直至每个阶段都没有任务。因为 NodeJS 的事件环不存在渲染部分,且不存在微任务队列,只有宏任务队列。而宏任务队列就分为 6 个阶段的。
NodeJS 事件环阶段
- Timers:setTimeout / setInterval
- Pending callbacks:执行延迟到下一个事件环迭代的 I/O 回调(内部机制使用)
- Idle,prepare:系统内部机制使用
- Poll:检查新的 I/O 事件与执行 I/O 回调
- Check:setImmediate
- Close callbacks: 关闭的回调函数(内部机制使用)
案例分析
```javascript // promise.then1 Promise.resolve().then(() => { console.log(1); });
// nextTick1 process.nextTick(() => { console.log(2); });
console.log(‘start’);
// readFile1 readFile(‘1.txt’, ‘utf-8’, () => { // setTimeout2 setTimeout(() => { console.log(3); }, 0);
// nextTick2 process.nextTick(() => { console.log(4); });
// setImmediate2 setImmediate(() => { console.log(5); });
console.log(6); });
console.log(7);
// setTimeout1 setTimeout(() => { console.log(8); }, 0);
// setImmediate1 setImmediate(() => { console.log(9); });
console.log(‘end’);

start 7 end
<br />只要执行阶段在转换之前或之后都要先清空微任务,在微任务中 nextTick 是优先于 promise.then 执行
start 7 end 2 1
微任务处理完成后,就处理 Node 事件环的任务<br /><br />这里 setImmediate1 cb 与 setTimeout1 cb 先后顺序不确定。尽管 setTimeout 的延迟时间为 0,也会有 >= 4 ms 的时间差。如果在 Poll 阶段时已经到 setTimeout1 的时间那么,setTimeout cb 会先进入主执行栈。相反在 Poll 阶段还未到时间,会进入 Check 阶段。把 setImmediate 的 cb 先进入主执行栈,再回到 Poll 阶段,把 setTimeout1 cb 进入主执行栈。
start 7 end 2 1 [ 8 9 ] 或 [ 9 8 ]
<br /><br />
start 7 end 2 1 [ 8 9 ] 或 [ 9 8 ] 6 4
<br />在 I/O 里面一定会先执行 setImmediate 回调
start 7 end 2 1 [ 8 9 ] 或 [ 9 8 ] 6 4 5 3 ```