Async coding tasks
This is the practical layer of asynchrony: not "what is a promise" but "build a working tool out of promises". Such tasks are prized in interviews because a short piece of code reveals your whole execution model — whether you understand that a promise settles once, that .then schedules a microtask, that setTimeout and setInterval behave differently under a slow network.
Each layer below is a distinct technique worth being able to write from memory and explain line by line. We dissect the mechanism, not a memorized answer: how the wrapper preserves this, why a remaining counter, why the tail promise swallows errors, why cancellation beats comparing terms. The layer order runs from the foundation (wrap a callback) to production patterns (cancellation, serialization).
Topic map
- Callback to promise — the
promisifywrapper, preservingthis, and the error-first convention. - Implementing combinators —
Promise.all/anyfrom scratch via a counter, an index array, andAggregateError. - Promise internals — the state machine, callback queues, and how
.thenschedules a microtask. - EventEmitter —
on/off/emiton aMapofSets, error isolation, and chaining viathis. - Fetch with retries — bounded retry with delay and a promise wrapper around
setTimeout. - Polling client — self-rescheduling
setTimeoutversussetIntervaland clearing the buffer only on success. - AbortController — cancelling a stale in-flight request and fixing the response-order race.
- Serialized writes — a tail promise that guarantees a queue with no concurrency and error isolation.
Common traps
| Mistake | Consequence |
|---|---|
Writing the promisify wrapper as an arrow function | The call-site this is lost |
push-ing results instead of writing by index | Array order scrambles on out-of-order settling |
setInterval for polling under a slow network | Requests stack on top of one another |
| Rescheduling before the request finishes | The overlap you wanted to remove comes back |
Advancing the queue tail without a .catch | One rejection breaks the whole later queue |
| Ignoring the search-suggest request race | A slow old response clobbers a newer one |
| Clearing the buffer before a successful send | A failed POST loses events silently |
Interview relevance
This is the "write a function at the board" format. The interviewer gives you a signature stub and asks for the implementation, then presses with follow-ups: "what if the input is empty?", "what if a request is slower than the interval?", "why a regular function, not an arrow?". The answers separate understanding the mechanism from a memorized template.
Typical checks:
- How to wrap an error-first callback in a promise, preserving
thisand the arguments. - How to implement a combinator that preserves order and handles the empty input correctly.
- Why self-rescheduling
setTimeoutis safer thansetIntervalunder a slow network. - How
AbortControllercancels a request and fixes the response-order race. - How a tail promise serializes writes and why it must swallow errors.
Common wrong answer: "await fetch(...) in a loop already runs in parallel" or "setInterval keeps data fresher more reliably". Both reveal a misunderstanding that await in a loop serializes steps, and that setInterval fires on the clock regardless of whether the previous request finished.