Question presented to candidate: "You are processing each chunk of a stream with an async operation that takes real time. Should you use the 'data' event or for await...of, and does it matter?"
What a strong answer should cover:
- Attaching a
"data"listener switches a Readable into flowing mode immediately β the stream starts emitting data as fast as it can produce it, regardless of how long your handler takes to process each chunk, because emitting an event does not wait for an async listener's returned promise. for await...ofiterates a Readable using its async iterator β each iteration explicitly requests the next chunk only once the current loop body (including anything itawaits) has finished. This is a pull-based model, not a push-based one.- The practical consequence: with the
"data"event, an async handler that is slower than the data arrives will fall behind with no built-in signal to slow production down β you would need to manuallypause()/resume()the stream to get that back. Withfor await...of, the pacing is naturally tied to how fast your loop body actually finishes. - A precise, honest nuance worth stating rather than glossing over:
for await...ofpacing the consumer's own request rate to the chunks is not automatically identical to the underlying source slowing its own production β a source can still fill its internal buffer up to itshighWaterMarkahead of what the consumer has asked for yet. True end-to-end backpressure to a slow/expensive source depends on that buffer filling up, which a small or fast source may never actually trigger. for await...ofcorrectly propagates a thrown error out of the loop as a normal exception (usable with try/catch), whereas the"data"event requires a separate"error"listener on the stream.for await...ofis generally the more modern, more correct default for anything where a slow, real async operation happens per chunk; the"data"event remains reasonable for a synchronous, fast handler with no meaningful per-chunk async work.
Clarifying questions expected:
- "Is the per-chunk processing synchronous and fast, or does it involve a real async operation (a DB write, a network call)?" β that is the deciding factor.
- "Does anything downstream need explicit pause()/resume() backpressure control if the 'data' event is used?" β a good answer flags this as the added complexity the event-based approach brings.
Code / implementation expected: Yes β timing the actual delivery of chunks under both approaches with an artificial async delay is the clearest way to make the difference concrete rather than assert it.