在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