event loop那些事兒

先來段代碼javascript

const p = new Promise((resolve, reject) => {
  console.log(1)
})
console.log(2);
setTimeout(function () {
    console.log(3);
}, 1000);
p.then((data) => {
  console.log(4)
})
console.log(5);
複製代碼

讓咱們來看看打印結果的順序java

1
2
5
4
3
複製代碼

由於javascript是單線程的,只有一個主線程。主線程會先執行同步代碼,異步操做會被放入一個任務隊列中。等到同步代碼執行完成以後,再執行異步任務。 常見的異步操做有:node

  • Ajax
  • DOM的事件操做
  • setTimeout
  • Promise的then方法
  • Node的讀取文件

異步任務又分爲宏任務微任務。 常見的宏任務有:setTimeoutsetIntervalsetImmediateMessageChannel 常見的微任務有:Promise的then方法process.nextTickMutationObserver瀏覽器

總結javascript執行順序以下: 1,如果同步任務,則 主線程中執行;若是是異步任務,就放到一個任務隊列裏 2,開始執行主線程中的同步任務,直到將主線程中的全部任務都走完,此時同步任務清空了 3,回過頭看異步隊列裏若是有異步任務完成了,就生成一個事件並註冊回調,放入主線程中 4,再返回第3步,直到異步隊列都清空,程序運行結束異步

這就是所謂的事件環機制,瀏覽器和node中的事件環機制有所不一樣。ui

瀏覽器中的事件環


在瀏覽器的執行環境中,老是先執行微任務,再執行宏任務,再來看看第一段代碼,爲何Promise的then方法在setTimeout以前執行?其根本原理就是由於Promise的then方法是一個微任務,而setTimeout是一個宏任務。 執行順序爲: 1,先執行微任務,清空微任務隊列 2,再執行宏任務,如宏任務中有微任務,則繼續執行微任務,直至清空微任務隊列 3,循環上述操做,直至全部任務完成spa

node中的事件環


node中的事件環.png

圖中每個階段都表明了一個宏任務隊列,在Node事件環中,優先執行微任務,微任務的運行時機是在每個「宏任務隊列」清空以後,在進入下一個宏任務隊列之間執行。這是和瀏覽器的最大區別。線程

與瀏覽器事件環有所不一樣的是:瀏覽器事件環是遇到微任務會清空整個微任務隊列。 Node事件環是清空完一個階段的宏任務隊列以後再清空微任務隊列。code

來看一段代碼:cdn

const fs = require('fs');

fs.readFile('./1.txt', (err, data) => {
    setTimeout(() => {
        console.log('timeout');
    });
    setImmediate(() => {
        console.log('immediate');
    });
    Promise.resolve().then(() => {
        console.log('Promise');
    });
});
複製代碼

執行結果爲:

Promise
immediate
timeout
複製代碼

代碼並不複雜,首先使用fs模塊讀取了一個文件,在回調的內部有兩個宏任務和一個微任務,微任務老是優於宏任務執行的,所以先輸出Promise。 可是以後的區別爲何先輸出immdiate?緣由就在於fs讀取文件的宏任務在上圖中的第4個輪詢階段,當第4個階段清空隊列以後,就該進入第5個check階段,也就是setImmediate這個宏任務所在的階段,而不會跳回第1個階段,所以先輸出immedate。

相關文章
相關標籤/搜索