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 の マイクロタスクキュー に追加されます。setTimeout、setImmediate コールバックは マクロタスクキュー に追加されます。
イベントループは、最初に process.nextTick キュー のタスクを実行し、次に Promise マイクロタスクキュー を実行し、最後に setTimeout または setImmediate マクロタスクキュー を実行します。
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 マイクロタスクキュー を処理し、bar を出力すると同時に process.nextTick キュー に zoo() を追加します。次に、追加されたばかりの zoo() を呼び出します。最後に、マクロタスクキュー の baz() が呼び出されます。
前述の原則は CommonJS のケースに当てはまりますが、ES Modules (例: mjs ファイル) では、実行順序が異なることに注意してください。
// start bar foo zoo bazこれは、ロードされる ES Module が非同期操作としてラップされるため、スクリプト全体が実際にはすでに Promise マイクロタスクキュー に存在するためです。したがって、Promise がすぐに解決されると、そのコールバックは マイクロタスクキュー に追加されます。Node.js は、他のキューに移動するまでキューをクリアしようとするため、最初に bar が出力されるのを確認できます。