Question presented to candidate: "You need to copy data from a readable source directly to a writable destination — a file to an HTTP response, for instance. What does .pipe() actually do, and why not just manually forward each chunk yourself?"
What a strong answer should cover:
.pipe()connects aReadablestream's output directly to aWritablestream's input: every chunk the readable produces is automatically written to the writable, without manually wiring up'data'event listeners and calling.write()yourself.- 📌 It automatically handles backpressure: if the destination writable is slower than the source readable,
.pipe()automatically pauses reading from the source until the destination signals it can accept more — manually forwarding'data'events yourself does not do this for free. stream.pipe()returns the destination stream, which is what enables chaining:source.pipe(transform1).pipe(transform2).pipe(destination), passing data through successive transform steps..pipe()'s well-known limitation, covered fully in its own dedicated question, is incomplete error propagation and cleanup: an error on the source does not automatically destroy the destination, which can leak open file handles/sockets —stream.pipeline()(Node's modern replacement) fixes exactly this.- A concrete, common real-world use:
fs.createReadStream(path).pipe(res)inside an HTTP handler streams a file directly to the client without ever loading the whole file into memory — connecting the file-system-read question and the readFile-vs-createReadStream question to this one. - A precise answer names
.pipe()as the original, still-common mechanism, while pointing tostream.pipeline()as the currently recommended choice for anything beyond the simplest, single-hop, already-correctly-error-handled case.
Clarifying questions expected:
- "Is proper error handling and cleanup across the whole chain a requirement here?" — if so,
stream.pipeline()is the better answer than raw.pipe(). - "Is this a single hop (source to destination) or a multi-step transform chain?" —
.pipe()'s chaining return value matters more for the latter.
Code / implementation expected: Yes — a real, working .pipe() call actually delivering data end to end is the concrete, convincing part of the answer.