setImmediate()を理解する

コードを非同期に、しかしできるだけ早く実行したい場合、選択肢の1つはNode.jsが提供する setImmediate() 関数を使用することです。

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

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

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

process.nextTick() に渡された関数は、現在の操作が終了した後、イベントループの現在のイテレーションで実行されます。これは、常に setTimeoutsetImmediate の前に実行されることを意味します。

0msの遅延を持つ 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 を出力すると同時に process.nextTickキューzoo() を追加します。次に、追加されたばかりの zoo() を呼び出します。最後に、マクロタスクキュー にある baz() が呼び出されます。

前述の原則はCommonJSの場合には当てはまりますが、ES Modules、例えば mjs ファイルでは実行順序が異なることに注意してください。

// start bar foo zoo baz

これは、ロードされるESモジュールが非同期操作としてラップされているため、スクリプト全体が実際には既に promisesマイクロタスクキュー に入っているからです。そのため、Promiseが即座に解決されると、そのコールバックは マイクロタスク キューに追加されます。Node.jsは他のキューに移る前にこのキューをクリアしようとするため、最初に bar が出力されるのがわかります。

読了時間
2分
作成者
コントリビュート
このページを編集