现在是凌晨3点17分,睡不着,应该说是昨天吧,刚学习的node的生命周期总结下;刚学Node,有不足的地方还望指教,下面进入正文
node的生命周期(事件循环)
node在处理各种事件时,首先从上往下将同步代码诶个进行处理,当遇到异步代码时,就会进入node的事件队列中去。
node的事件循环主要从timers、poll、check、nextTick、和promise这几个来进行监听与处理。当然完整的事件循环,不止这几个,中间还有好多步骤。
这个简化的图说明了timers,poll,和check的处理顺序,而nextTick和promise这两个在图的正中间,是因为这两个比较特殊。下面会根据这张图进行诶个解释
event loop
负责检测是否还有异步的事件未进行处理;只有全部处理完,才会到结束那一步;而如果还有没有处理的事件就会进入timers
timers
主要负责计时器线程,负责监听计时器是否到执行时间,到了的话,就会执行计时器里面的函数。列如setTimeout和setInterval都是在该线程执行的。
当进入timers时,node仅仅看一眼,有没有需要执行的事件,如果有就执行,没有就进入poll,不会因为计时器的时间没有到而等待。
poll
可以说,除了timers,check,nextTick和promise,其他的异步事件全部都在这里执行。
当进入poll队列时,即使没有要执行的事件,poll也会一直等下去,一直等到有需要执行的事件,或者其他事件队列里面有需要执行的事件时才会进行下一步到check队列。否则就一直等,直到等到node设置的最大时间限制后仍然没有要执行的事件,那么才会进入下一步
setTimeout(()=>{
console.log('hello world')
},2000)
上面这行代码node在生命周期执行的顺序为
- 判断是否有同步代码,当然是没有同步代码的
- 查看event loop,看下是否有异步事件需要执行。此时发现有setTimeout,所以有异步需要执行
- 进入timers队列,查看是否有需要执行的事件;(当进入timers时,可能还没到2秒,所以没有事件要执行)
- 进入poll队列,查看是否有需要执行的事件;(当然也是没有,所以等待,一直等到2秒后,计时器线程有事件需要执行了,进入下一步)
- 查看check队列(也是没有需要执行的事件,接着下一步)
- 回到event loop,在次判断是否有需要执行的事件(计时器线程的事件还是没有执行,所以有需要执行的事件,进行下一步)
- 进入timers队列,此时发现有需要执行的事件,将事件拿出来执行。此时才会输出hello world。执行完后在次判断该队列中是否还有事件需要继续执行,有就全部诶个执行,没有进行下一步
- 进入poll队列,等待node规定的最大时间后,还是没有需要执行的,进行下一步
- 进入check队列,还是没有要执行的,下一步
- 回到event loop,判断是否还有异步事件,此时就没有了。进入下一步结束。
我们从上面的步骤中可以发现,在当计时器的时间到达两秒的时候,并不是立刻执行计时器里面的函数,而是先执行当下这个线程的事件,然后下一个线程,直到再次进入timers线程时才会执行这个函数,那么也就说明,计时器规定的是两秒后执行,然而因为要走流程,也就导致了计时器不能在2秒后准时执行,实际执行的时间会大于2秒。
check
check主要用于监听setImmediate事件
setImmediate事件会直接进入check队列,不会像timers那样只有时间到了才会进入队列
有个有趣的事情,请往下看
setTimeout(() => { console.log('setTimeout') }, 1);
setImmediate(() => { console.log('setImmediate') });
我们将setTimeout的时间设置为1毫秒,按理,按上面的执行顺序来说的话,进入timer时,计时器还在计时中,所以应该进入下一步poll,然后进入check执行setImmediate事件,之后才是setTimeout,然而实际上我们执行时的结果是
有时setTimeout会比setImmediate先输出,原因是当执行timers之前计算机稍微卡顿一下的话,那么就可能在timers时计时器已经走完了1毫秒。所以,当时间特别短的时候,先输出setTimeout还是setImmediate,就变的不确定了
nextTick和promise
nextTick和promise,不论是在timers队列,还是poll,又或是check队列,只要这两个队列里面有事件没有处理,就一定会去处理这两个队列里面的事件,只有这两个队列没有任何事件后,才会去处理其他的异步队列。 当在event loop判断完后,实际上第一步应该是查看nextTick然后查看promise,之后才是timers
nextTick的优先级高于promise,所以nextTick一定是最先去处理的
这也就是为什么nextTick和promise在上面的图中的最中心,因为他俩不会按照事件循环的顺序去执行,而是只要有就会优先去执行。
总结
- nextTick和promise,可以说就是js里面的微队列,而timers、poll、check都是处于宏队列中
- nextTick的优先级高于promise
- setImmediate的执行顺序本来应该要高于setTimeout的,但因为计算机的执行速度,导致可能setTimeout比setImmediate更快的执行
- setTimeout的真正执行时间并能在设置的时间准时执行,大多都会比设置的时间要根久
- 整个事件循环,最费时间的是在poll时,因为,当没有要执行的东西时,他会一直等着