學習筆記之事件迴圈-Event loop

hiSky發表於2018-05-28

前言

本文僅以記錄瀏覽器環境的event loop 和 node環境中的event loop的瞭解過程,如果錯誤,歡迎指正

瀏覽器環境

Event Loop是指在js執行環境中存在主執行執行緒和任務佇列(Task Queue),其中所有同步任務都在主執行執行緒中形成一個執行棧,所有非同步任務都會放到任務佇列中

具體執行過程:
1. 主執行緒執行同步任務, 在主執行緒執行的過程中,不斷行程堆疊並執行出棧入棧的操作
2. 如果主執行緒任務沒有完成,繼續完成,如果完成了就執行下一步
3. 系統讀取佇列任務, 開始執行
4. 不斷迴圈

而我們的非同步任務中,分為巨集任務(macrotask) 和微任務(microtask),
執行順序
1. 先取出macrotask任務佇列中的第一個任務進行執行
2. 取出Macrotask Queue中一個任務執行。
3. 取出Microtask Queue中任務執行直到清空。

學習筆記之事件迴圈-Event loop


node

執行任務為:
1. timers 階段: 這個階段執行setTimeout和setInterval預定的callback;
2. I/O callbacks 階段: 執行除了 close事件的callbacks、被timers設定的callbacks、setImmediate()設定的callbacks這些之外的callbacks;
3. idle, prepare 階段: 僅node內部使用;
4. poll 階段: 獲取新的I/O事件, 適當的條件下node將阻塞在這裡;
5. check 階段: 執行setImmediate() 設定的callbacks;
6. close callbacks 階段: 執行socket.on('close', ...)這些 callback


學習筆記之事件迴圈-Event loop


參考文件,對比 setImmediate 和 process.nextTick()

setImmediate 和 process.nextTick()

setImmediate(() => console.log('immediate1'));
setImmediate(() => console.log('immediate2'));

setTimeout(() => console.log('setTimeout1'), 1000);
setTimeout(() => {
    console.log('setTimeout2');
    process.nextTick(() => console.log('nextTick1'));
}, 0);
setTimeout(() => console.log('setTimeout3'), 0);

process.nextTick(() => console.log('nextTick2'));
process.nextTick(() => {
    process.nextTick(console.log.bind(console, 'nextTick3'));
});
process.nextTick(() => console.log('nextTick4'));
複製程式碼
執行結果:

在控制檯中執行node index.js,得到的結果如下:

nextTick2
nextTick4
nextTick3
setTimeout2
setTimeout3
nextTick1
immediate1
immediate2
setTimeout1
複製程式碼
結論

在node中,nextTick的優先順序高於setTimeout和setImmediate(),所以會先執行nextTick裡面的資訊列印。
但是對於巢狀的nextTick,會慢於同步的nextTick,所以nextTick4會先於nextTick3
然後開始一個Event Loop過程,首先執行timer階段,而此時setTimeout所需要等待的時間是0,所以立即執行setTimeout2和setTimeout3裡面的邏輯。而setTimeout1由於設定了執行時間,不滿足執行條件,被放到下一輪Event Loop
當前Event Loop執行到check階段,於是列印出immediate1、immediate2
執行後面的Event Loop,當setTimeout1達到執行條件時執行

基於node事件的event loop,我們使用事件也變得方便快捷

event.emit('eventType', () => {})
event.on('eventType', () => {})


相關文章