libuv Phases
O loop de eventos do libuv executa fases em uma ordem fixa a cada tick - conhecer a sequência explica o drift de timers, o comportamento do setImmediate e quando os callbacks de I/O são disparados.
Busque em todas as páginas da documentação
O loop de eventos do libuv executa fases em uma ordem fixa a cada tick - conhecer a sequência explica o drift de timers, o comportamento do setImmediate e quando os callbacks de I/O são disparados.
Ordem das fases (uma iteração do loop):
timers → pending → idle/prepare → poll → check → close callbacks
↑ microtasks são drenados entre as fases ↑
import { setTimeout, setImmediate } from 'node:timers';
setTimeout(() => console.log('timer'), 0);
setImmediate(() => console.log('immediate'));Quando usar isso:
setImmediate vs setTimeout(0)data de sockets são executados em relação aos timersimport { readFile } from 'node:fs';
import { setTimeout, setImmediate } from 'node:timers';
readFile(__filename, () => {
console.log('1: Callback de I/O (fase poll)');
setTimeout(() => console.log('2: timer'), 0);
setImmediate(() => console.log('3: immediate (fase check)'));
});
setTimeout(() => console.log('4: timer externo'), 0);
setImmediate(() => console.log('5: immediate externo'));Padrão de saída típico:
readFile: 1, depois 3 (immediate), depois 2 (timer).O que isso demonstra:
poll.setImmediate em um callback de I/O é executado na fase check da mesma iteração.setTimeout, setInterval).setImmediate.close (por exemplo, socket.on('close')).| Fase | Exemplos de API | Notas |
|---|---|---|
| timers | setTimeout, setInterval | Atraso mínimo, não exato sob carga |
| poll | fs.readFile, socket.on('data') | Pode bloquear se nenhum outro trabalho estiver agendado |
| check | setImmediate | Executa após poll no mesmo tick |
| close | server.close, manipulação de limpeza | Última chance para liberação de recursos |
import { setImmediate } from 'node:timers';
// Adia o trabalho até depois dos callbacks de I/O neste tick
function deferAfterIo(fn: () => void): void {
setImmediate(fn);
}setTimeout(fn, 100) dispara exatamente em 100ms - as fases e a carga adicionam drift. Correção: use relógios monótonos para prazos, não apenas a contagem do timer.setImmediate - a fase check nunca cede para I/O. Correção: use setImmediate uma vez por item, agrupe o trabalho ou use workers.| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
queueMicrotask | Executar antes da próxima macrotask, após a pilha atual | Você precisa esperar o poll de I/O terminar |
setImmediate | Adiar após a fase de poll atual | Precisão de tempo sub-milissegundo necessária |
setTimeout | Agendamento baseado em tempo com tolerância | Agendamento exato sob carga pesada de CPU |
| Mensagem de thread Worker | Trabalho de CPU fora da thread principal | Adiar simples de algumas linhas |
Um ciclo completo através de timers, pending, idle/prepare, poll, check e close - com microtasks drenadas entre as fases.
Na fase check, imediatamente após a fase poll ser concluída naquela iteração.
Timers disparam apenas quando o loop atinge a fase de timers. Trabalho síncrono bloqueante ou poll saturado atrasam essa fase.
O manipulador data do socket na fase poll, depois as microtasks de quaisquer Promises que ele cria, depois os immediates da fase check.
Ela pode esperar por I/O com um timeout computado. Se timers ou immediates estiverem prontos, ela expira e continua.
nextTick não é uma fase do libuv - ele é executado entre as fases e antes das microtasks de Promise. O uso excessivo bloqueia I/O.
Ao desativar servidores e sockets - callbacks close liberam handles. Importante para um desligamento gracioso.
Não - o libuv sempre percorre o ciclo. Você influencia quais callbacks são enfileirados para cada fase.
Ideias semelhantes de microtask/macrotask; Node adiciona setImmediate, process.nextTick, e integração de I/O diferente via libuv.
NODE_DEBUG=timer rastreia inserções e disparos de timer - útil localmente, barulhento em produção.
Sim - callbacks de conclusão de I/O de rede são agendados através do libuv como node:http.
Cada await de middleware cede microtasks; o envio da resposta dispara I/O na fase poll. Middleware síncrono longo bloqueia todas as fases.
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 e NestJS 11.
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026