1. 程式人生 > 實用技巧 >(轉載)JS中的事件迴圈♻️

(轉載)JS中的事件迴圈♻️

轉載於YIong https://www.cnblogs.com/alex-415/p/10557452.html

什麼是事件迴圈

針對JS程式碼執行的單執行緒特點, 為了解決非同步執行問題, 有必要在同步程式碼執行完畢之後, 對非同步程式碼返回結果進行處理. 這時候的處理方式, 處理順序就是一個核心問題. 所以才有了事件迴圈執行機制, 簡要介紹如下:

  1. 所有同步任務都在主執行緒上的棧中執行。

  2. 主執行緒之外,還存在一個"任務佇列"(task queue)。只要非同步任務有了執行結果,就在"任務佇列"之中放置一個事件。

  3. 一旦"棧"中的所有同步任務執行完畢,系統就會讀取"任務佇列",選擇出需要首先執行的任務(由瀏覽器決定,並不按序)。

非同步任務

1.MacroTask(巨集觀Task) setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering

2.MicroTask(微觀任務) process.nextTick, Promise, Object.observe, MutationObserver

規範:

每個瀏覽器環境,至多有一個event loop。
一個event loop可以有1個或多個MacroTask queue,而僅有一個 MicroTask Queue。
一個task queue是一列有序的task, 每個task定義時都有一個task source,從同一個task source來的task必須放到同一個task queue,從不同源來的則被新增到不同佇列。
tasks are scheduled,所以瀏覽器可以從內部到JS/DOM,保證動作按序發生。
Microtasks are scheduled,Microtask queue 在當前 task queue 的結尾執行。microtask中新增的microtask也被新增到Microtask queue的末尾並處理。

注: event loop的每個turn,是由瀏覽器決定先執行哪個task queue。這允許瀏覽器為不同的task source設定不同的優先順序,比如為使用者互動設定更高優先順序來使使用者感覺流暢。

例項


function ELoop() { // 當前任務 let p = new Promise((resolve, reject) => { console.log("current Task") resolve(); }); let nextP;

    setTimeout(() => {
        console.log("MacroTask_1");
        nextP.then(() => {
            // 第一次執行時,這段程式碼並沒有執行到。
            console.log("MicroTask_promise_1"); //第一個MicroTask
        })
        console.log("MacroTask_1 end")
    }, 0) // 第一個 MacroTask

    setTimeout(() => {
        console.log("MacroTask_2");
        console.log("MacroTask_2 end")
    }, 0) // 第二個MacroTask

    nextP = p.then(() => {
        console.log("MicroTask_promise_2"); //第一個MicroTask
    }).then(() => {
        console.log("MicroTask_promise_3"); // 第二個MicroTask
    })

    console.log("current Task end")
}

ELoop();

/**輸出結果:
current Task
current Task end
MicroTask_promise_2
MicroTask_promise_3
MacroTask_1
MacroTask_1 end
MicroTask_promise_1
MacroTask_2
MacroTask_2 end
**/