Asynchronous JavaScript
JavaScript runs on a single thread, so "long" work — a server request, a timer, a file read — cannot simply block and wait. Instead you describe what to do when the result is ready, while the engine keeps running the rest of your code. Historically this was expressed with callbacks, then promises, and today with async/await syntax, which sits on top of those same promises yet reads like ordinary sequential code.
The main trap of this topic is thinking asynchrony means parallel threads. It does not: one stack, one queue, everything in turn. await does not stop the thread — it pauses only its own function and yields control. A promise settles exactly once and is then immutable. A rejection is a stored reason, not a thrown stack. Below are the layers dissecting each mechanism, from a callback to a push-based observable.
Topic map
- Callbacks — a function passed as an argument to be invoked later, the error-first convention, and why nesting breeds callback hell.
- Promises — an object for an eventual result, the three states, one-way settlement, and
.thenchains. - Promise combinators —
all,race,allSettled,anyand how each reacts to success and failure. - async / await — sugar over promises, function suspension, and resumption via a microtask.
- Error handling —
try/catcharoundawait,throwas reject, and how unhandled rejections get lost. - Promise detection — thenable duck-typing instead of
instanceof, and howPromise.resolveadopts state. - Observables — a lazy push stream of many values versus an eager one-shot promise.
Common traps
| Mistake | Consequence |
|---|---|
Believing await blocks the thread | False model — only the function pauses, the thread is free |
| Thinking a callback is always asynchronous | Many APIs (Array.map, some libraries) call the callback synchronously |
| Expecting a settled promise to change state | Settlement is one-way and final; the value is fixed forever |
Forgetting return inside .then | The chain's value flow breaks; the next handler gets undefined |
Relying on instanceof Promise | Breaks across realms (iframes, workers) — use .then duck-typing |
Not awaiting or .catch-ing a promise | The rejection becomes an unhandled rejection and is lost silently |
Confusing race and any | race is first to settle either way; any is first to fulfill |
Interview relevance
Asynchrony is the most frequent block of questions for mid/senior front-end roles. The interviewer checks not syntax knowledge but your execution model: whether you understand there is one thread, that await is a suspension point with a microtask continuation, and that a promise is an immutable one-shot result container.
Typical checks:
- The three promise states and that settlement is final and one-time.
- That an
asyncfunction always returns a promise, andawaitpauses only that function. - The difference between the four combinators and how they react to the first failure.
- How async errors are caught and how they get lost — what an unhandled rejection is.
- How an observable (lazy, multi-value, cancelable) differs from a promise.
Common wrong answer: "await stops the whole program until the value arrives." In fact await pauses only the current async function, returns control to the caller, and schedules the continuation as a microtask — all the remaining synchronous code runs first.