淺探EventLoop事件循環機制

何爲Event Loop

event loop是一個執行模型,是js異步運行的核心。js是一門單線程的語言,意味着js沒法進行多線程操做,可是js中的異步功能能夠徹底模擬多線程。javascript

宏隊列 macrotask

一些異步任務的回調會依次進入macro task queue,等待後續被調用,這些異步任務包括java

  • setTimeout
  • setInterval
  • requestAnimationFrame (瀏覽器獨有)
  • I/O
  • UI rendering (瀏覽器獨有)

微隊列,microtask

一些異步任務的回調會依次進入micro task queue,等待後續被調用,這些異步任務包括:promise

  • process.nextTick (Node獨有)
  • Promise
  • Object.observe
  • MutationObserver
  • Event Loop執行機制

這張圖將瀏覽器的Event Loop完整的描述了出來,如下是javascript執行代碼的具體順序

  1. 執行全局Script同步代碼
  2. 全局Script代碼執行完畢後,調用棧Stack會清空;
  3. 微隊列中取出位於隊首的回調任務,放入調用棧Stack中執行,執行完後microtask queue長度減1;
  4. 繼續取出位於隊首的任務,放入調用棧Stack中執行,以此類推,直到把microtask queue中的全部任務都執行完畢。若是在執行microtask的過程當中,又產生了microtask,那麼會加入到隊列的末尾,也會在這個週期被調用執行;
  5. microtask queue中的全部任務都執行完畢,此時microtask queue爲空隊列,調用棧Stack也爲空;
  6. 取出宏隊列macrotask queue中位於隊首的任務,放入Stack中執行; 執行完畢後,調用棧Stack爲空;
  7. 重複第3-6個步驟;

要點

由此概括出兩個要點:瀏覽器

  1. 宏隊列macrotask一次只從隊列中取一個任務執行,執行完後就去執行微任務隊列中的任務;
  2. 微任務隊列中全部的任務都會被依次取出來執行,直到微任務隊列爲空;

接下來是一個代碼實例bash

console.log(1);

setTimeout(() => {
  console.log(2);
  Promise.resolve().then(() => {
    console.log(3)
  });
});

new Promise((resolve, reject) => {
  console.log(4)
  resolve(5)
}).then((data) => {
  console.log(data);
})

setTimeout(() => {
  console.log(6);
})

console.log(7);
複製代碼

輸出結果:1 4 7 5 2 3 6 整個流程爲:多線程

  1. 執行全局同步代碼(promise中在resolve或reject前的也算) 因此輸出1,4,7
  2. 執行微隊列代碼 此時的微隊列中的任務爲Promise中的resolve(5)則輸出5
  3. 執行宏隊列中的隊首任務(注意只執行一個宏任務),此時的隊首任務爲代碼中第一個setTimeOut,則輸出了2。在執行這個任務時又產生了一個新的微任務。
  4. 執行新產生的微隊列中的任務,因此輸出了3
  5. 微任務隊列爲空,宏隊列中還有一個任務,因而輸出6
相關文章
相關標籤/搜索