1. 程式人生 > 實用技巧 >巨集任務、微任務

巨集任務、微任務

參考1:https://www.cnblogs.com/lucy-xyy/p/11652286.html

參考2:https://www.cnblogs.com/yugege/p/9598265.html

事件迴圈機制

JavaScript 語言的一大特點就是單執行緒,也就是說,同一個時間只能做一件事,但是一個任務耗時太長,那麼後面的任務就需要等待,為了解決這種情況,將任務分為了同步任務和非同步任務,而非同步任務又可以分為微任務和巨集任務。

同步和非同步任務分別進入不同的執行環境,同步的進入主執行緒,即主執行棧,非同步的進入 Event Queue (任務佇列)。主執行緒內的任務執行完畢為空,會去 Event Queue 讀取對應的任務,推入主執行緒執行。 上述過程的不斷重複就是我們說的 Event Loop (事件迴圈)。

所以非同步操作都是放到事件迴圈佇列裡面,等待主執行棧來執行的,也並沒有專門的非同步執行執行緒。

巨集任務和微任務

task分為兩大類, 分別是 Macro Task (巨集任務)和 Micro Task(微任務), 並且每個巨集任務結束後, 都要清空所有的微任務。

macro task巨集任務主要包含:script( 整體程式碼)、setTimeout、setInterval、I/O、UI 互動事件、setImmediate(Node.js 環境)

micro task微任務主要包含:Promise函式中的then語句、async中的await語句、MutaionObserver、process.nextTick(Node.js 環境)

補充:在 node 環境下,process.nextTick 的優先順序高於 Promise函式中的then語句

從圖中可以看到,巨集任務執行順序優先於微任務,所以JS執行順序為:script>清空微任務>巨集任務>清空微任務>巨集任務>清空微任務……直至清空任務佇列

舉個栗子

async function async1() {
    console.log(2); // 順序4.同步程式碼最先執行,輸出2
    await fn(); // 順序5:await會阻塞await後面程式碼的執行,但不阻塞await表示式,同時await會跳出async函式
    console.log(7); //
順序10:await執行完畢,且await之前不存在微任務,執行後續同步程式碼及await時生成的微任務,輸出7 } function fn() { // 順序6:執行fn,輸出3,await跳出async函式讓出執行緒,執行async後面的程式碼 console.log(3); } console.log(1); // 順序1.由上而下,同步程式碼最先執行,輸出1 setTimeout(function () { // 順序2.setTimeout為巨集任務,進入任務佇列進行等待執行 console.log(10); // 順序13.無同步程式碼、無微任務,開始執行下一個巨集任務,輸出10 }, 0) async1(); // 順序3.同步程式碼,執行方法async1 new Promise(function (resolve) { console.log(4); // 順序7:執行Promise同步程式碼,輸出4,記錄.then為微任務1,進入佇列等待執行 resolve(); }).then(function () { console.log(8); // 順序11.無同步程式碼,依次執行剩餘微任務,輸出8 }); new Promise(function (resolve) { console.log(5); // 順序8:執行Promise同步程式碼,輸出5,記錄.then為微任務2,進入佇列等待執行 resolve(); }).then(function () { console.log(9); // 順序12.無同步程式碼,執行剩餘微任務2,輸出9 }); console.log(6); // 順序9:執行同步程式碼,輸出6