JS是單線程語言,始終只有一個線程執行JS代碼(Web Worker沒有改變JS單線程的本質),對於異步操做,是經過事件循環(Event Loop)來實現的。瀏覽器
每一個異步操做都是一個任務,任務分爲宏任務和微任務bash
其中, setImmediate
和process.nextTick
是Node獨有的,UI交互事件
確定是瀏覽器獨有的。異步
特別是第二點,可能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的事件循環,每一輪有六個階段測試
1. Timer階段ui
執行可用的setTimeout/setInterval回調spa
2. I/O callbacks階段線程
執行可用的I/O回調,除了setTimeout
、setInterval
、setImmediate
、Close callbacks
都屬於這個階段。
3. idle, prepare階段
這兩個階段主要是Node作一些內部操做,忽略。
4. Poll階段
這是輪詢階段,若是沒有可用的setTimeout/setInterval/setImmediate/Close callbacks回調,會一直停留在這個階段,等待I/O回調。
這個階段不會一直停留,達到必定條件後,會到下一個階段。
5. Check階段
專門用於執行setImmediate
。
6. Close callbacks階段
關閉請求在這裏執行(socket.on('close', ()=>{})),這個階段就像一個清理階段。
若是事件循環還活着,就繼續下一輪循環。
歡迎關注個人微博@狂刀二