Когда вы хотите выполнить какой-то кусок кода асинхронно, но как можно скорее, один из вариантов — использовать функцию setImmediate(), предоставляемую Node.js:
setImmediate(() => {
// выполнить что-то
});Любая функция, переданная как аргумент setImmediate(), — это колбэк, который выполняется на следующей итерации event loop.
Чем setImmediate() отличается от setTimeout(() => {}, 0) (с передачей таймаута 0 мс), а также от process.nextTick() и Promise.then()?
Функция, переданная в process.nextTick(), выполнится на текущей итерации event loop, после завершения текущей операции. Это значит, что она всегда выполнится до setTimeout и setImmediate.
Колбэк setTimeout() с задержкой 0 мс очень похож на setImmediate(). Порядок выполнения будет зависеть от разных факторов, но оба они выполнятся на следующей итерации event loop.
Колбэк process.nextTick добавляется в process.nextTick queue. Колбэк Promise.then() добавляется в promises microtask queue. Колбэк setTimeout, setImmediate добавляется в macrotask queue.
Event loop сначала выполняет задачи в process.nextTick queue, затем выполняет promises microtask queue, а затем выполняет macrotask queue.
Вот пример, показывающий порядок между 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(), затем вызовет foo() из process.nextTick queue. После этого он обработает promises microtask queue, которая печатает bar и одновременно добавляет zoo() в process.nextTick queue. Затем он вызовет только что добавленный zoo(). В конце вызывается baz() из macrotask queue.
Вышеописанный принцип верен для случаев CommonJS, но имейте в виду, что в ES-модулях, например в mjs-файлах, порядок выполнения будет другим:
// start bar foo zoo bazТак происходит потому, что загружаемый ES-модуль обёрнут как асинхронная операция, и таким образом весь скрипт фактически уже находится в promises microtask queue. Поэтому, когда промис немедленно разрешается, его колбэк добавляется в очередь microtask. Node.js попытается очистить эту очередь, прежде чем переходить к любой другой, а значит, вы увидите, что сначала выводится bar.