js事件循環機制 (Event Loop)

1、JavaScript是單線程單併發語言

  • 什麼是單線程javascript

    主程序只有一個線程,即同一時間片段內其只能執行單個任務。java

  • 爲何選擇單線程?git

    JavaScript的主要用途是與用戶互動,以及操做DOM。這決定了它只能是單線程,不然會帶來很複雜的同步問題。github

  • 單線程意味着什麼?promise

    單線程就意味着,全部任務都須要排隊,前一個任務結束,纔會執行後一個任務。若是前一個任務耗時很長,後一個任務就須要一直等着。這就會致使IO操做(耗時但cpu閒置)時形成性能浪費的問題。瀏覽器

  • 如何解決單線程帶來的性能問題?併發

    答案是異步!主線程徹底能夠無論IO操做,暫時掛起處於等待中的任務,先運行排在後面的任務。等到IO操做返回告終果,再回過頭,把掛起的任務繼續執行下去。因而,全部任務能夠分紅兩種,一種是同步任務(synchronous),另外一種是異步任務(asynchronous)異步

    注: 當主線程阻塞時,任務隊列仍然是可以被推入任務的async

2、事件循環Event Loop

一、JavaScript 內存模型圖oop

 

二、JavaScript 代碼執行機制

  • 全部同步任務都在主線程上的棧中執行。

  • 主線程以外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。

  • 一旦"棧"中的全部同步任務執行完畢,系統就會讀取"任務隊列",選擇出須要首先執行的任務(由瀏覽器決定,並不按序)。

三、事件循環(EventLoop)

 

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設置不一樣的優先級,好比爲用戶交互設置更高優先級來使用戶感受流暢。

4、實例

```javascript

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
**/

```

github:https://github.com/Hasyou99/Daily-summary

相關文章
相關標籤/搜索