原文能夠訪問個人主頁:原文地址 若是文章對您有幫助,您的star是對我最好的鼓勵~node
簡要介紹:談談promise.resove,setTimeout,setImmediate,process.nextTick在EvenLoop隊列中的執行順序git
event loop都不陌生,是指主線程從「任務隊列」中循環讀取任務,好比github
例1:
setTimeout(function(){console.log(1)},0);
console.log(2)
//輸出2,1
複製代碼
在上述的例子中,咱們明白首先執行主線程中的同步任務,當主線程任務執行完畢後,再從event loop中讀取任務,所以先輸出2,再輸出1。promise
event loop讀取任務的前後順序,取決於任務隊列(Job queue)中對於不一樣任務讀取規則的限定。好比下面一個例子:bash
例2:
setTimeout(function () {
console.log(3);
}, 0);
Promise.resolve().then(function () {
console.log(2);
});
console.log(1);
//輸出爲 1 2 3
複製代碼
先輸出1,沒有問題,由於是同步任務在主線程中優先執行,這裏的問題是setTimeout和Promise.then任務的執行優先級是如何定義的。oop
在Job queue中的隊列分爲兩種類型:macro-task和microTask。咱們舉例來看執行順序的規定,咱們設ui
macro-task隊列包含任務: a1, a2 , a3 micro-task隊列包含任務: b1, b2 , b3spa
執行順序爲,首先執行marco-task隊列開頭的任務,也就是 a1 任務,執行完畢後,在執行micro-task隊列裏的全部任務,也就是依次執行***b1, b2 , b3***,執行完後清空micro-task中的任務,接着執行marco-task中的第二個任務,依次循環。線程
瞭解完了macro-task和micro-task兩種隊列的執行順序以後,咱們接着來看,真實場景下這兩種類型的隊列裏真正包含的任務(咱們以node V8引擎爲例),在node V8中,這兩種類型的真實任務順序以下所示:code
macro-task隊列真實包含任務:
script(主程序代碼),setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task隊列真實包含任務: process.nextTick, Promises, Object.observe, MutationObserver
由此咱們獲得的執行順序應該爲:
script(主程序代碼)—>process.nextTick—>Promises...——>setTimeout——>setInterval——>setImmediate——> I/O——>UI rendering
在ES6中macro-task隊列又稱爲ScriptJobs,而micro-task又稱PromiseJobs
例3:
setTimeout(function () {
console.log(3);
}, 0);
Promise.resolve().then(function () {
console.log(2);
});
console.log(1);
複製代碼
咱們先以第1小節的例子爲例,這裏遵循的順序爲:
script(主程序代碼)——>promise——>setTimeout 對應的輸出依次爲:1 ——>2————>3
例子4:
setTimeout(function(){console.log(1)},0);
new Promise(function(resolve,reject){
console.log(2);
resolve();
}).then(function(){console.log(3)
}).then(function(){console.log(4)});
process.nextTick(function(){console.log(5)});
console.log(6);
//輸出2,6,5,3,4,1
複製代碼
這個例子就比較複雜了,這裏要注意的一點在定義promise的時候,promise構造部分是同步執行的,這樣問題就迎刃而解了。
首先分析Job queue的執行順序:
script(主程序代碼)——>process.nextTick——>promise——>setTimeout
I) 主體部分: 定義promise的構造部分是同步的, 所以先輸出2 ,主體部分再輸出6(同步狀況下,就是嚴格按照定義的前後順序)
II)process.nextTick: 輸出5
III)promise: 這裏的promise部分,嚴格的說實際上是promise.then部分,輸出的是3,4
IV) setTimeout : 最後輸出1
綜合的執行順序就是: 2——>6——>5——>3——>4——>1
setTimeout(function(){console.log(1)},0);
new Promise(function(resolve,reject){
console.log(2);
setTimeout(function(){resolve()},0)
}).then(function(){console.log(3)
}).then(function(){console.log(4)});
process.nextTick(function(){console.log(5)});
console.log(6);
//輸出的是 2 6 5 1 3 4
複製代碼
這種狀況跟咱們(2)中的例子,區別在於promise的構造中,沒有同步的resolve,所以promise.then在當前的執行隊列中是不存在的,只有promise從pending轉移到resolve,纔會有then方法,而這個resolve是在一個setTimout時間中完成的,所以3,4最後輸出。