当node在主线程执行完同步任务后,会检查是否有异步操作在等待,如果有则启动事件循环,否则退出。事件循环的六阶段定时器执行由setTimeout和setInterval设置回调pendingcallbacks执行延迟I/O回调idle,准备内部操作poll获取新的I/O事件(如connection,request),执行I/O相关回调(close回调、timer、check除外)检查执行setImmediate设置的callbackclose回调执行一些关闭操作回调(eg.socket.destroy)。这些异步操作可以在入口脚本中添加到指定模块(如timer模块),eg://entry.jsconsole。log(1);//异步操作,准备好后,将其回调加入定时器队列setTimeout(()=>console.log('timeoutcallback'),0);console.log(2);//异步操作,其回调加入到检查队列中setImmediate(()=>console.log('immediatecallback'));控制台日志(3);当一个异步操作就绪时(例如定时器到达指定时间),异步操作的回调将被添加到相应阶段的队列中(例如定时器的回调被添加到定时器阶段的队列中)),等待执行。执行顺序节点按照上图所示的顺序执行每个stage,当队列为空时,会进入下一个stage。poll阶段执行时,按照如下逻辑执行:当poll队列不为空时,会执行其队列中的回调,直到为Empty或达到系统限制。当poll队列为空,没有timer就绪时,如果有setImmediate就绪,则结束poll阶段,转入check阶段计算时间,直到下一个timer就绪。在此之前,停止在轮询阶段,等待回调被添加到它的队列中。当轮询完成其队列的执行时,它将检查是否有定时器就绪。如果是,则结束poll阶段,继续当前循环的执行,然后进入下一个循环执行readytimer.setTimeout和setImmediate在非I/O周期执行setTimeout和setImmediate时,顺序取决于当前系统环境。如果系统运行到事件循环开始,超过定时器设置的时间(setTimeout的第二个参数默认值为0,但节点不满足0ms执行定时器的要求,实际值从1ms),则setTimeout先于setImmediate执行,否则setImmediate先于setTimeout.setTimeout(()=>console.log('timeout'),0);setImmediate(()=>console.log('immediate'));//output:12or21在I/O周期执行时,setImmediate先于setTimeout执行。因为执行I/O操作是在poll阶段。poll阶段结束后,转入check阶段。constfs=require('fs');fs.readFile(__filename,()=>{setTimeout(()=>console.log('timeout'),0);setImmediate(()=>console.log('immediate'));})//输出:immediatetimeoutprocess.nextTickprocess.nextTick在所有同步操作完成后,事件循环开始前,执行setTimeout(()=>console.log('timeout'),0);process.nextTick(()=>console.log('nextTick'));console.log('entry')beforeexecutingeachstage);//output:entrynextTicktimeoutsetTimeout(()=>{console.log('timeout1');process.nextTick(()=>console.log('nextTick'));},0);setTimeout(()=>console.log('timeout2'));//输出:timeout1timeout2nextTicksetTimeout(()=>{console.log('wrap-timeout');setTimeout(()=>console.log('inner-timeout'),0);process.nextTick(()=>{console.log('wrap-nextTick');process.nextTick(()=>console.log('inner-nextTick'));});},0);//输出:wrap-timeoutwrap-nextTickinner-nextTickinner-timeout
