Entendendo setImmediate()
Quando você deseja executar algum código de forma assíncrona, mas o mais rápido possível, uma opção é usar a função setImmediate()
fornecida pelo Node.js:
setImmediate(() => {
// faça algo
})
Qualquer função passada como argumento setImmediate()
é um callback que é executado na próxima iteração do loop de eventos.
Como setImmediate()
difere de setTimeout(() => {}, 0)
(passando um timeout de 0ms), e de process.nextTick()
e Promise.then()
?
Uma função passada para process.nextTick()
será executada na iteração atual do loop de eventos, após o término da operação atual. Isso significa que sempre será executada antes de setTimeout
e setImmediate
.
Um callback setTimeout()
com um atraso de 0ms é muito semelhante a setImmediate()
. A ordem de execução dependerá de vários fatores, mas ambos serão executados na próxima iteração do loop de eventos.
Um callback process.nextTick
é adicionado à fila process.nextTick queue. Um callback Promise.then()
é adicionado à fila de microtarefas de promises microtask queue. Um callback setTimeout
, setImmediate
é adicionado à fila de macrotarefas macrotask queue.
O loop de eventos executa as tarefas na fila process.nextTick queue primeiro, e então executa a fila de microtarefas de promises promises microtask queue, e então executa a fila de macrotarefas setTimeout
ou setImmediate
macrotask queue.
Aqui está um exemplo para mostrar a ordem entre setImmediate()
, process.nextTick()
e 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
Este código primeiro chamará start()
, depois chamará foo()
na fila process.nextTick queue. Depois disso, ele irá lidar com a fila de microtarefas de promises promises microtask queue, que imprime bar e adiciona zoo()
na fila process.nextTick queue ao mesmo tempo. Então ele chamará zoo()
que acabou de ser adicionado. No final, o baz()
na fila de macrotarefas macrotask queue é chamado.
O princípio mencionado acima é válido em casos CommonJS, mas lembre-se que em módulos ES, por exemplo, arquivos mjs
, a ordem de execução será diferente:
// start bar foo zoo baz
Isso ocorre porque o módulo ES sendo carregado é encapsulado como uma operação assíncrona, e assim todo o script já está na fila de microtarefas de promises promises microtask queue
. Então, quando a promise é resolvida imediatamente, seu callback é anexado à fila microtask queue
. O Node.js tentará limpar a fila até mover para qualquer outra fila, e portanto você verá que ele imprime bar primeiro.