Skip to content

setImmediate()について

非同期で、できるだけ早くコードを実行したい場合、Node.jsが提供するsetImmediate()関数を用いることができます。

javascript
setImmediate(() => {
    // 何らかの処理
});

setImmediate()の引数として渡された関数は、イベントループの次のイテレーションで実行されるコールバックです。

setImmediate()は、setTimeout(() => {}, 0)(0msのタイムアウトを渡す場合)、process.nextTick()Promise.then()とどう違うのでしょうか?

process.nextTick()に渡された関数は、現在の操作が終了した後に、イベントループの現在のイテレーションで実行されます。つまり、setTimeoutsetImmediateよりも常に先に実行されます。

0msの遅延を伴うsetTimeout()コールバックは、setImmediate()と非常に似ています。実行順序は様々な要因に依存しますが、どちらもイベントループの次のイテレーションで実行されます。

process.nextTickコールバックはprocess.nextTickキューに追加されます。Promise.then()コールバックはPromiseのmicrotaskキューに追加されます。setTimeoutsetImmediateコールバックはmacrotaskキューに追加されます。

イベントループは、まずprocess.nextTickキューのタスクを実行し、次にPromiseのmicrotaskキューを実行し、その後setTimeoutまたはsetImmediatemacrotaskキューを実行します。

setImmediate()process.nextTick()Promise.then()の順序を示す例を以下に示します。

javascript
const baz = () => console.log('baz');
const foo = () => console.log('foo');
const zoo = () => console.log('zoo');
const start = () => {
  console.log('start');
  setImmediate(baz);
  new Promise((resolve, reject) => {
    resolve('bar');
  }).then(resolve => {
    console.log(resolve);
    process.nextTick(zoo);
  });
  process.nextTick(foo);
};
start();
// start foo bar zoo baz

このコードは、まずstart()を呼び出し、次にprocess.nextTickキューfoo()を呼び出します。その後、Promiseのmicrotaskキューを処理し、barを出力し、同時にprocess.nextTickキューzoo()を追加します。次に、追加されたzoo()を呼び出します。最後に、macrotaskキューbaz()が呼び出されます。

上記の原則はCommonJSの場合に当てはまりますが、ESモジュール(例:mjsファイル)では実行順序が異なることに注意してください。

javascript
// start bar foo zoo baz

これは、ロードされるESモジュールが非同期操作としてラップされているため、スクリプト全体が既にPromiseのmicrotaskキューにあるためです。したがって、Promiseがすぐに解決されると、そのコールバックはmicrotaskキューに追加されます。Node.jsは他のキューに移動するまでキューのクリアを試みるため、最初にbarが出力されます。