欢迎回来,在第一篇文章中, 描述了NodeJS事件循环的总体情况,在这一节中,将通过代码实例详细讨论三种重要的队列。它们是,timers, immediates 和 process.nextTick的回掉.文章指引Event LoopTimers、 Immediates 、 Next Ticks (本文)Promises、Next-Ticks、Immediates处理 I/O最佳的事件循环练习在 Node v11中timers、microtasks发生的改变I/O饥饿 例子一这带来了一个新问题。使用process递归/重复地向nextTick队列添加事件。nextTick函数可能导致I/O和其他队列永远饿死。我们可以使用下面的简单脚本模拟这个场景。const fs = require(‘fs’);function addNextTickRecurs(count) { let self = this; if (self.id === undefined) { self.id = 0; } if (self.id === count) return; process.nextTick(() => { console.log(process.nextTick call ${++self.id}); addNextTickRecurs.call(self, count); });}addNextTickRecurs(Infinity);setTimeout(console.log.bind(console, ‘omg! setTimeout was called’), 10);setImmediate(console.log.bind(console, ‘omg! setImmediate also was called’));fs.readFile(__filename, () => { console.log(‘omg! file read complete callback was called!’);});console.log(‘started’);您可以看到输出是一个无限循环的nextTick回调调用,以及setTimeout、setImmediate 和fs.readFile。从未调用readFile回调.startedprocess.nextTick call 1process.nextTick call 2process.nextTick call 3process.nextTick call 4process.nextTick call 5process.nextTick call 6process.nextTick call 7process.nextTick call 8process.nextTick call 9process.nextTick call 10process.nextTick call 11process.nextTick call 12….例二const fs = require(‘fs’);fs.readFile(__filename, () => { setTimeout(() => { console.log(’timeout’) }, 0); setImmediate(() => { console.log(‘immediate’) })});接下来我们来看一下它的执行流程在开始时,这个程序使用fs.readFile异步读取当前文件。它提供一个回调函数,在读取文件后触发。然后事件循环开始。一旦读取文件后,它将在事件循环的I/O队列中添加事件(要执行的回调)。由于没有要处理的其他事件,Node正在等待任何I/O事件。然后,它将在I/O队列中看到文件读取事件并执行它。在回调的执行过程中,timer 被添加到timer 堆中,并且Immediates被添加到Immediates 队列中现在我们知道事件循环处于I/O阶段。由于没有要处理的任何I/O事件,因此事件循环将移动到immediate阶段,然后立即执行immediate 回调。在事件循环的下一个循环中,它将看到过期的timer 并执行timer 回调。例三setImmediate(() => console.log(’this is set immediate 1’));setImmediate(() => console.log(’this is set immediate 2’));setImmediate(() => console.log(’this is set immediate 3’));setTimeout(() => console.log(’this is set timeout 1’), 0);setTimeout(() => { console.log(’this is set timeout 2’); process.nextTick(() => console.log(’this is process.nextTick added inside setTimeout’));}, 0);setTimeout(() => console.log(’this is set timeout 3’), 0);setTimeout(() => console.log(’this is set timeout 4’), 0);setTimeout(() => console.log(’this is set timeout 5’), 0);process.nextTick(() => console.log(’this is process.nextTick 1’));process.nextTick(() => { process.nextTick(console.log.bind(console, ’this is the inner next tick inside next tick’));});process.nextTick(() => console.log(’this is process.nextTick 2’));process.nextTick(() => console.log(’this is process.nextTick 3’));process.nextTick(() => console.log(’this is process.nextTick 4’));首先会有如下的一些事件被添加到事件队列中3 immediates5 timer 回掉5 next tick 回掉当事件循环开始时,它将注意到next tick队列并开始处理next tick的回调。在执行第二个next tick回调期间,一个新的next tick回调被添加到next tick队列的末尾,并将在next tick队列的末尾执行。将执行过期timer 的回调。在第二个timer 回调函数的执行过程中,一个事件被添加到next tick队列中。一旦执行了所有过期timer 的回调,事件循环将看到下一个timer 队列中有一个事件(这是在执行第二个timer 回调期间添加的)。然后事件循环将执行它。由于没有要处理的I/O事件,因此事件循环将移动到即时队列并处理即时队列。执行结果是下面这个样子this is process.nextTick 1this is process.nextTick 2this is process.nextTick 3this is process.nextTick 4this is the inner next tick inside next tickthis is set timeout 1this is set timeout 2this is set timeout 3this is set timeout 4this is set timeout 5this is process.nextTick added inside setTimeoutthis is set immediate 1this is set immediate 2this is set immediate 3Referencehttps://jsblog.insiderattack…. (自备梯子)