setImmediate vs setTimeout
setImmediate schedules a callback after the poll phase (check phase). setTimeout(fn, 0) schedules a callback after a minimum delay (≥1ms) in the timers phase. Both defer execution, but to different event loop phases.
setImmediate = 'I'll do it right after this meeting (poll phase).' setTimeout(0) = 'I'll do it first thing tomorrow morning (next timers phase).' Inside an I/O callback, you're already in the meeting, so setImmediate always wins the race home.
When called from the main module (outside I/O callbacks), their execution order is non-deterministic because it depends on whether the timer's 1ms minimum has elapsed by the time the timers phase runs. Inside an I/O callback, setImmediate always executes before setTimeout(fn, 0) because the event loop has already passed the timers phase for that iteration and will reach check before looping back to timers.
The 1ms minimum timer resolution is a libuv implementation detail inherited from OS timer APIs. On Linux, the minimum timer resolution is typically 1ms; on Windows it can be up to 15ms. Under load, the timers phase may see a setTimeout(fn, 0) as not yet expired even though nominally 0ms have passed. For guaranteed post-I/O, post-poll ordering, setImmediate is the correct tool. setImmediate also has a meaningful performance advantage in high-throughput scenarios because it doesn't involve timer heap management in libuv.
setImmediate fires in the check phase (after poll); setTimeout(fn, 0) fires in the timers phase (start of loop). From the main module their order is non-deterministic. Inside an I/O callback, setImmediate always fires first. When you need to defer work until after I/O callbacks in the current iteration, setImmediate is the correct choice.
Assuming setTimeout(fn, 0) fires before setImmediate anywhere is wrong. The order is only guaranteed inside I/O callbacks. Benchmarks and tests that rely on their relative ordering from the main script will produce flaky results across machines and Node versions.