Question presented to candidate: "Both process.nextTick() and setImmediate() schedule a callback to run 'soon' rather than synchronously. What is actually different about them, and can you prove it rather than just state it?"
What a strong answer should cover:
process.nextTick(fn)schedulesfnonto a microtask queue that is drained completely, including anything it recursively schedules, before the event loop proceeds to its next phase. It runs before Promise microtasks, and before any timer or I/O callback.setImmediate(fn)schedulesfnto run in the check phase — a real, distinct stop the event loop makes on every lap, after the poll (I/O) phase.- 📌 The verifiable, not just definitional, distinction: because
nextTickis a microtask queue, an unbounded recursiveprocess.nextTick()call can starve the event loop entirely — I/O callbacks never get a turn, because the loop never advances past the microtask-draining step. The identical recursive pattern usingsetImmediate()cannot do this, because check is a real phase that only runs once per lap, always preceded by a poll-phase visit. - Relative to
setTimeout(fn, 0): inside an I/O callback,setImmediateis guaranteed to run before asetTimeout(fn, 0)scheduled at the same point, because poll transitions to check before looping back to timers. At the top level of a script, the order between the two is not guaranteed and depends on process startup timing. - Practical uses:
process.nextTick()is for guaranteeing a callback runs before the event loop continues at all — commonly, ensuring an API always calls its callback asynchronously (even when the result is already available) so callers can rely on consistent, never-synchronous behavior.setImmediate()is for deferring work to after the current poll phase, to avoid hogging I/O processing — a common choice for breaking up a large synchronous chunk of work into smaller pieces that let I/O interleave. - A good answer explicitly avoids over-generalizing "nextTick runs first" into "nextTick is always what you want" — the starvation risk above is a real reason to prefer
setImmediatefor recursive/repeated scheduling.
Clarifying questions expected:
- "Is this about deferring one callback, or about something that recurses/repeats?" — the starvation risk only matters for the latter.
- "Does the use case need to run before the event loop continues at all, or just after I/O has had a turn?" — this is exactly the nextTick-vs-setImmediate decision.
Code / implementation expected: Yes — the starvation test (recursive nextTick vs recursive setImmediate, racing a real I/O callback) is the single most convincing, concrete demonstration of the distinction.