在Node学习过程当中,不可避免的须要对事件循环机制作深刻理解,其中Macrotask(大型任务)和Microtask(小型任务)比较使人困惑,在一番google以后,我发现了几篇资料能比较好地解释他们的原理。所以在这里汇总+搬运一下。html
在Nodejs事件循环机制中,有任务两个队列:Macrotask队列和Microtask队列。在一个事件循环里,这两个队列会分两步执行,第一步会固定地执行一个(且仅一个)Macrotask任务,第二步会执行整个Microtask队列中的全部任务。而且,在执行Microtask队列任务的时候,也容许加入新的Microtask任务,直到全部Microtask任务所有执行完毕,才会结束循环。node
Macrotasks通常包括: setTimeout
, setInterval
, setImmediate
, I/O, UI rendering;
Microtasks通常包括: process.nextTick
, Promises
, Object.observe
, MutationObserver
。异步
从一个事件循环开始,到结束会经历如下步骤:函数
检查Macrotask队列,选择其中最先加入(即最老的)的任务X,设置为“目前运行的任务”。若是任务X不存在,那么直接跳到步骤4。oop
运行任务X,即运行对应的回调函数。学习
设置“目前运行的任务”为null,从Macrotask队列中移除任务X。google
检查Microtask队列:code
1)选择其中最老的任务a,若是任务a不存在,直接结束Microtask队列。 2)设置任务a为“目前运行的任务”,并执行。 3)设置“目前运行的任务”为null,从Microtask队列中移除任务a。 4)选择下一个最老的任务b,跳到步骤2)。 5)直到队列里没有剩余的任务,结束队列。
跳回步骤1,检查下一个Macrotask任务。server
关于事件循环步骤,参考文档中的《理解 Node.js 事件循环》这篇文章讲的很是好也很是详细,强烈推荐想了解的同窗必定要看。htm
能够这样简单理解:若是你想让一个任务当即执行,那么就把它设置为Microtask,除此以外都用Macrotask比较好。由于能够看出,虽然Node是异步非阻塞的,但在一个事件循环中,Microtask的执行方式基本上就是用同步的。
相信读到这里你已经意识到,若是一个Microtask队列太长,或者执行过程当中不断加入新的Microtask任务,会致使下一个Macrotask任务好久都执行不了。结果就是,你可能会遇到UI一直刷新不了,或者I/O任务一直完成不了。
应该是考虑到了这一点,至少Microtask任务中的process.nextTick
任务,是被设置了(在一个事件循环中的)最大调用次数的,叫process.maxTickDepth
。默认是1000。必定程度上避免了上述状况。
理解 Node.js 事件循环
Difference between microtask and macrotask within an event loop context