Понимание setImmediate()
Если вам нужно выполнить фрагмент кода асинхронно, но как можно скорее, одним из вариантов является использование функции setImmediate()
, предоставляемой Node.js:
setImmediate(() => {
// выполнить что-либо
})
Любая функция, переданная в качестве аргумента setImmediate()
, является обратным вызовом, который выполняется на следующей итерации цикла событий.
Чем setImmediate()
отличается от setTimeout(() => {}, 0)
(передача таймаута 0 мс), а также от process.nextTick()
и Promise.then()
?
Функция, переданная в process.nextTick()
, будет выполнена на текущей итерации цикла событий после завершения текущей операции. Это означает, что она всегда будет выполняться перед setTimeout
и setImmediate
.
Обратный вызов setTimeout()
с задержкой 0 мс очень похож на setImmediate()
. Порядок выполнения будет зависеть от различных факторов, но оба будут запущены на следующей итерации цикла событий.
Обратный вызов process.nextTick
добавляется в очередь process.nextTick queue. Обратный вызов Promise.then()
добавляется в очередь микрозадач promises microtask queue. Обратный вызов setTimeout
, setImmediate
добавляется в очередь макрозадач macrotask queue.
Цикл событий сначала выполняет задачи в очереди process.nextTick queue, затем выполняет очередь микрозадач promises microtask queue, а затем выполняет очередь макрозадач setTimeout
или setImmediate
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. Поэтому, когда промис немедленно разрешается, его обратный вызов добавляется в очередь микрозадач. Node.js попытается очистить очередь, прежде чем перейти к любой другой очереди, и поэтому вы увидите, что сначала выведется bar.