天天看點

Javascript事件循環Event Loop詳解

1、基本概念

1. 所有同步任務都在主線程上執行,形成一個執行棧(execution context stack)。

2. 主線程之外,還存在一個“任務隊列”(task queue),隻要異步

任務有了運作結果,就在“任務隊列”中放置一個事件(包括事件綁定、ajax和定時器)。

3. 一旦“執行棧”中的所有同步任務執行完畢,系統就會讀取“任務隊

列”,看看裡邊有哪些事件。哪些對應的異步任務,于是結束等待

狀态,進入“執行棧”開始執行。

4. 主線程不斷重複上邊的第三步。

Javascript事件循環Event Loop詳解

2、 如果添加了Promise又如何工作呢?

我們知道,Promise的回調函數不是傳入的,而是使用then來調用的。是以,Promise中定義的函數應該是馬上執行的,then才是其回調函數,放入queue隊列中。

在參考的文章中還提到了一個重要的概念:

macro-task包括:script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering。

micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver

執行順序:函數調用棧清空隻剩全局執行上下文,然後開始執行所有的micro-task。當所有可執行的micro-task執行完畢之後。循環再次執行macro-task中的一個任務隊列,執行完之後再執行所有的micro-task,就這樣一直循環。

再看一個例子:

(function test() {
    setTimeout(function() {console.log(4)}, 0);
    new Promise(function executor(resolve) {
        console.log(1);
        for( var i=0 ; i<10000 ; i++ ) {
            i == 9999 && resolve();
        }
        console.log(2);
    }).then(function() {
        console.log(5);
    });
    console.log(3);
})()
           

具體的過程可以看上面那篇文章。大概過程如下:

  1. 遇到setTimeout,交給其他子產品執行,執行完後回調放入macro-task中
  2. 遇到Promise,立即執行裡面的function,輸出1。
  3. 循環開始,遇到resolve(),修改Promise狀态為fulfill。繼續執行,輸出2。
  4. 遇到then,将回調放入micro-task中。
  5. 繼續執行,輸出3。
  6. call stack執行完畢了。開始執行micro-task中的回調函數,輸出5。
  7. micro-task執行完畢,開始執行macro-task中的回調函數,輸出4。
  8. 結束。

原文連結:https://blog.csdn.net/qq_31628337/article/details/71056294

參考:https://blog.csdn.net/qq_31628337/article/details/71056294

http://www.ruanyifeng.com/blog/2014/10/event-loop.html

繼續閱讀