setImmediate()
について
非同期で、できるだけ早くコードを実行したい場合、Node.jsが提供するsetImmediate()
関数を用いることができます。
setImmediate(() => {
// 何らかの処理
});
setImmediate()
の引数として渡された関数は、イベントループの次のイテレーションで実行されるコールバックです。
setImmediate()
は、setTimeout(() => {}, 0)
(0msのタイムアウトを渡す場合)、process.nextTick()
、Promise.then()
とどう違うのでしょうか?
process.nextTick()
に渡された関数は、現在の操作が終了した後に、イベントループの現在のイテレーションで実行されます。つまり、setTimeout
やsetImmediate
よりも常に先に実行されます。
0msの遅延を伴うsetTimeout()
コールバックは、setImmediate()
と非常に似ています。実行順序は様々な要因に依存しますが、どちらもイベントループの次のイテレーションで実行されます。
process.nextTick
コールバックはprocess.nextTickキューに追加されます。Promise.then()
コールバックはPromiseのmicrotaskキューに追加されます。setTimeout
、setImmediate
コールバックはmacrotaskキューに追加されます。
イベントループは、まずprocess.nextTickキューのタスクを実行し、次にPromiseのmicrotaskキューを実行し、その後setTimeout
またはsetImmediate
のmacrotaskキューを実行します。
setImmediate()
、process.nextTick()
、Promise.then()
の順序を示す例を以下に示します。
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
ファイル)では実行順序が異なることに注意してください。
// start bar foo zoo baz
これは、ロードされるESモジュールが非同期操作としてラップされているため、スクリプト全体が既にPromiseのmicrotaskキュー
にあるためです。したがって、Promiseがすぐに解決されると、そのコールバックはmicrotaskキュー
に追加されます。Node.jsは他のキューに移動するまでキューのクリアを試みるため、最初にbar
が出力されます。