JS事件循環

JS是單線程語言,始終只有一個線程執行JS代碼(Web Worker沒有改變JS單線程的本質),對於異步操做,是經過事件循環(Event Loop)來實現的。瀏覽器

任務

每一個異步操做都是一個任務,任務分爲宏任務微任務bash

  • 宏任務:script、setTimeout、setInterval、setImmediate、I/O、UI交互事件
  • 微任務:Promise(Promise的then和catch)、process.nextTick、Object.observe(已廢棄)

其中, setImmediateprocess.nextTick是Node獨有的,UI交互事件確定是瀏覽器獨有的。異步

澄清兩個誤區

  • 事件循環和JS代碼是在一個線程中運行的
  • 通過測試,無論是瀏覽器端仍是Node端,每一個宏任務執行完後,都會去清除微任務

特別是第二點,可能Node作了更新(當前時間是2019-01-13,Node v11.4.0),以下面代碼,無論瀏覽器仍是Node,都會輸出:1 2 3 4socket

setTimeout(function () {
  new Promise(function (resolve) {
    console.log(1);
    resolve();
  }).then(function () {
    console.log(2);
  });
});

setTimeout(function () {
  new Promise(function (resolve) {
    console.log(3);
    resolve();
  }).then(function () {
    console.log(4);
  });
});

// delay(); // 爲了消除定時器最小延遲帶來的影響,能夠執行一下耗時操做,確保上面兩個setTimeout都觸發了

function delay() {
  for (let i = 0; i < 1000000000; i++) {}
}
複製代碼

定時器的最小延遲問題見這裏oop

差別

瀏覽器的事件循環是HTML5定義的規範,Node的事件循環是libuv庫實現的,但截至目前(2019-01-13),二者的表現基本一致,Node的事件循環比瀏覽器要複雜,下面看Node的事件循環。post

Node的事件循環

Node的事件循環,每一輪有六個階段測試

1. Timer階段ui

執行可用的setTimeout/setInterval回調spa

2. I/O callbacks階段線程

執行可用的I/O回調,除了setTimeoutsetIntervalsetImmediateClose callbacks都屬於這個階段。

3. idle, prepare階段

這兩個階段主要是Node作一些內部操做,忽略。

4. Poll階段

這是輪詢階段,若是沒有可用的setTimeout/setInterval/setImmediate/Close callbacks回調,會一直停留在這個階段,等待I/O回調。

這個階段不會一直停留,達到必定條件後,會到下一個階段。

5. Check階段

專門用於執行setImmediate

6. Close callbacks階段

關閉請求在這裏執行(socket.on('close', ()=>{})),這個階段就像一個清理階段。

若是事件循環還活着,就繼續下一輪循環。

最後

歡迎關注個人微博@狂刀二

相關文章
相關標籤/搜索