Serialize async writes so no two run concurrently
Implement writeFileQueued(write) that returns a function enqueue(data). The underlying write(data) returns a promise and must never run concurrently — each call must wait for the previous one to settle before starting. Requirements: calls run in the order they were enqueued; enqueue returns a promise that settles with that specific write's result or error; one write's failure must not break the queue for later writes.
function writeFileQueued(write) {
// return enqueue(data)
// your code here
}
Write the implementation.
Keep a tail promise for the queue end, starting as Promise.resolve(). In enqueue(data) chain the write: const run = tail.then(() => write(data)). Advance tail = run.catch(() => {}) so one rejection cannot poison later writes, and return run to the caller.
- ✗Advancing the tail without a
catch, so one rejection breaks the whole queue - ✗Returning the shared tail so every caller sees another write's result
- ✗Starting writes concurrently instead of chaining each onto the previous
- →Why must the tail swallow errors while the returned promise keeps them?
- →How would you add a max-queue-length limit that rejects new enqueues?
Solution
A single queue tail; each write chains onto the previous.
function writeFileQueued(write) {
let tail = Promise.resolve(); // end of the queue
return function enqueue(data) {
const run = tail.then(() => write(data)); // wait for previous, then write
tail = run.catch(() => {}); // tail swallows errors → queue survives
return run; // caller sees its own result/error
};
}
How it works
tail always points at the completion of the last enqueued write. A new write only starts inside tail.then(...), so write never runs until the previous one settles — no concurrency, order preserved. tail is advanced with a .catch(() => {}) version so a rejection does not poison the chain for future writes. The caller gets back run (without the catch), so they receive their own result or error.