理解 setImmediate()

當你想非同步執行某段程式碼,但又希望儘快執行時,一個選擇是使用 Node.js 提供的 setImmediate() 函式。

(() => {
  // run something
});

任何作為 setImmediate() 引數傳遞的函式都是一個回撥,它會在事件迴圈的下一次迭代中執行。

setImmediate()setTimeout(() => {}, 0)(傳遞 0 毫秒超時)、process.nextTick()Promise.then() 有何不同?

傳遞給 process.nextTick() 的函式將在事件迴圈的當前迭代中,在當前操作結束後執行。這意味著它將總是在 setTimeoutsetImmediate 之前執行。

一個延遲為 0 毫秒的 setTimeout() 回撥與 setImmediate() 非常相似。執行順序將取決於多種因素,但它們都將在事件迴圈的下一次迭代中執行。

process.nextTick 回撥被新增到 process.nextTick 佇列中。Promise.then() 回撥被新增到 promises 微任務佇列中。setTimeoutsetImmediate 回撥被新增到 宏任務佇列中。

事件迴圈首先執行 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

閱讀時間
2 分鐘
作者
貢獻
編輯此頁面