promise和setTimeout的執行順序?談談瀏覽器中的Event Loop
阿新 • • 發佈:2020-12-14
promise和setTimeout都是處理非同步回撥的,那麼到底誰先誰後呢?
我們來看一個例子:
(function test() {
setTimeout(function() {console.log(1)}, 0);
new Promise(function executor(resolve) {
console.log(2);
for( var i=0 ; i<10000 ; i++ ) {
i == 9999 && resolve();
}
console.log(3);
}).then(function() {
console.log(4);
});
console.log(5);
})()
Copy
答案是 2 3 5 4 1,而且在控制檯編譯的時候,看到1和其他的數字不同,函式的返回值都出現了才執行。那麼,為什麼會這樣呢?
當我們執行JS程式碼的時候,遇到非同步程式碼時,會被掛起並加入到Task佇列中。當執行棧為空的時候,就在Task佇列中拿出需要執行的程式碼。不同的任務會被分配到不同的佇列,我們可以把它分為 微任務(microtask) 和 巨集任務(macrotask)。
- 微任務包括
process.nextTick
,promise
,MutationObserver
。 - 巨集任務包括
script
,setTimeout
,setInterval
,setImmediate
,I/O
UI rendering
。
瀏覽器的執行Even Loop執行順序如下:
- 首先執行同步程式碼,這也屬於巨集任務。
- 執行完同步程式碼後,查詢是否有巨集任務中的非同步程式碼需要執行。(這個時候只是查詢,並沒有執行哦)
- 執行完所有的微任務,並完成頁面渲染
- 開始下一輪EventLoop
- 如果 2 步驟中查詢到要執行的非同步程式碼,這時候執行。如setTimeout函式
這樣,上圖的情況就能解釋了。