1. 程式人生 > 實用技巧 >promise和setTimeout的執行順序?談談瀏覽器中的Event Loop

promise和setTimeout的執行順序?談談瀏覽器中的Event Loop

promisesetTimeout都是處理非同步回撥的,那麼到底誰先誰後呢?

我們來看一個例子:

(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.nextTickpromiseMutationObserver
  • 巨集任務包括scriptsetTimeoutsetIntervalsetImmediateI/O
    UI rendering

瀏覽器的執行Even Loop執行順序如下:

  1. 首先執行同步程式碼,這也屬於巨集任務。
  2. 執行完同步程式碼後,查詢是否有巨集任務中的非同步程式碼需要執行。(這個時候只是查詢,並沒有執行哦)
  3. 執行完所有的微任務,並完成頁面渲染
  4. 開始下一輪EventLoop
  5. 如果 2 步驟中查詢到要執行的非同步程式碼,這時候執行。如setTimeout函式

這樣,上圖的情況就能解釋了。