理解 setImmediate()
當你想非同步執行某段程式碼,但又希望儘快執行時,一個選擇是使用 Node.js 提供的 setImmediate() 函式。
(() => {
// run something
});
任何作為 setImmediate() 引數傳遞的函式都是一個回撥,它會在事件迴圈的下一次迭代中執行。
setImmediate() 與 setTimeout(() => {}, 0)(傳遞 0 毫秒超時)、process.nextTick() 和 Promise.then() 有何不同?
傳遞給 process.nextTick() 的函式將在事件迴圈的當前迭代中,在當前操作結束後執行。這意味著它將總是在 setTimeout 和 setImmediate 之前執行。
一個延遲為 0 毫秒的 setTimeout() 回撥與 setImmediate() 非常相似。執行順序將取決於多種因素,但它們都將在事件迴圈的下一次迭代中執行。
process.nextTick 回撥被新增到 process.nextTick 佇列中。Promise.then() 回撥被新增到 promises 微任務佇列中。setTimeout、setImmediate 回撥被新增到 宏任務佇列中。
事件迴圈首先執行 process.nextTick 佇列中的任務,然後執行 promises 微任務佇列中的任務,最後執行 宏任務佇列中的任務。
這裡有一個例子來展示 setImmediate()、process.nextTick() 和 Promise.then() 之間的順序。
const = () => .('baz');
const = () => .('foo');
const = () => .('zoo');
const = () => {
.('start');
();
new ((, ) => {
('bar');
}).( => {
.();
.();
});
.();
};
();
// start foo bar zoo baz
這段程式碼將首先呼叫 start(),然後在 process.nextTick 佇列中呼叫 foo()。之後,它將處理 promises 微任務佇列,這會打印出 bar 並同時將 zoo() 新增到 process.nextTick 佇列中。然後它會呼叫剛剛新增的 zoo()。最後,呼叫 宏任務佇列中的 baz()。
上述原則在 CommonJS 情況下成立,但請記住,在 ES 模組中(例如 mjs 檔案),執行順序會有所不同。
// start bar foo zoo baz
這是因為正在載入的 ES 模組被包裝成一個非同步操作,因此整個指令碼實際上已經位於 promises 微任務佇列中。所以當 promise 立即解決時,它的回撥被追加到 微任務 佇列。Node.js 會嘗試清空該佇列,直到移動到任何其他佇列,因此你會看到它首先輸出 bar。