JavaScript事件循環(Event Loop)

任務隊列

首先我們要知道關於JavaScript的一些規則:

  • JavaScript是被設計成單線程的
  • JavaScript的任務分爲同步任務和異步任務

圖片描述

同步任務都在主線程上執行,形成一個執行棧。當主線程執行完之後,運行微任務(micro-task)隊列的任務直到爲空,更新UI渲染(會根據瀏覽器的邏輯,決定要不要馬上執行更新),然後再運行宏任務(macro-task)隊列的任務直到爲空......流程如下:

(主線程上的執行棧同步任務,可以視爲是第一個macro-task隊列)
 macro-task -> micro-task(如果存在) -> 更新UI渲染

如此無限循環上面的流程,是爲JavaScript的Event Loop機制。

宏任務

宏任務(macro-task),宏任務隊列可以有一個或者多個。每個任務都有一個任務源(task source),源自同一個任務源的 task 必須放到同一個任務隊列,從不同源來的則被添加到不同隊列。

宏任務:script(全局任務), setTimeout, setInterval, setImmediate, I/O, UI rendering.

微任務

微任務(micro-task),微任務在渲染更新前,macro-task之後執行。
關於async和await,因爲async await 本身就是promise+generator的語法糖。所以await後面的代碼是microtask。實際上await是一個讓出線程的標誌。await後面的表達式會先執行一遍,將await後面的代碼加入到microtask中,然後就會跳出整個async函數來執行後面的代碼。

微任務:process.nextTick, Promise, Object.observer, MutationObserver,await.

舉例

        async function async1() {
            console.log('async1 start');
            await async2();
            console.log('async1 end');
        }
        async function async2() {
            console.log('async2');
        }

        console.log('script start');

        setTimeout(function () {
            console.log('setTimeout');
        }, 0)

        async1();

        new Promise(function (resolve) {
            console.log('promise1');
            resolve();
        }).then(function () {
            console.log('promise2');
        });
        console.log('script end');

流程如下:

  1. console打印script start
  2. setTimeout,是異步宏任務,進入macro-task setTimeout隊列
  3. async1(), async await函數,在await之前是同步任務,直接執行,打印async1 start
  4. await async2(),await後面的表達式會先執行一遍,打印async2
  5. await 下面的代碼視爲promise.then,進入micro-task promise隊列,跳出async1()
  6. new Promise,promise內,.then之前的代碼是直接執行的,所以打印promise1
  7. .then內函數進入micro-task promise隊列後
  8. console,直接打印script end
  9. 主線程執行棧運行完並清空了,micro-task進入執行棧,分別按順序執行打印async1 endpromise2
  10. micro-task隊列清空,macro-task進入執行棧,打印setTimeout,程序運行完畢。

完整結果如下:

/**
 *script start
 *async1 start
 *async2
 *promise1
 *script end
 *async1 end
 *promise2
 *setTimeout
 */

該結果基於chrome 版本 72.0.3626.121。因爲async await標準有所改變,所以稍老版本的瀏覽器結果可能不一致。

參考:
https://jakearchibald.com/201...
https://github.com/Advanced-F...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章