Async: Promise and await
The event loop, async/await, running in parallel with Promise.all.
Updated
What synchronous and asynchronous mean
Synchronous = each line waits for the previous one to finish. Asynchronous = you start a slow operation (a network request, a timer, reading a file) and carry on with something else; the result comes later.
Why it matters: JS in the browser runs on a single thread — the same one that paints the page and responds to clicks. If it waited synchronously 2 seconds for a request, the page would freeze for 2 seconds.
The event loop — how it works
- The call stack — the code running right now.
- Slow operations are handed to the browser (network, timers), which does them in parallel.
- When one finishes, its callback goes into a queue.
- The event loop takes from the queue only when the stack is empty.
There are two queues, with different priorities:
| Queue | What goes in | Priority |
|---|---|---|
| microtask | Promise .then, await, queueMicrotask |
all of them run before the next macrotask |
| macrotask | setTimeout, setInterval, events, I/O |
one per turn |
console.log(1)
setTimeout(() => console.log(4)) // macrotask
Promise.resolve().then(() => console.log(3)) // microtask
console.log(2)
// 1, 2, 3, 4What a Promise is
A Promise is an object that represents a value that's coming — like an order ticket: you don't have the food yet, but you have something you can wait on.
A Promise has 3 states:
| State | Means |
|---|---|
pending |
still in progress |
fulfilled |
done, it has a value |
rejected |
it failed, it has an error |
Once it has settled (fulfilled or rejected), the state never changes again.
const wait = ms => new Promise(resolve => setTimeout(resolve, ms))
fetch('/api/user')
.then(res => res.json()) // runs on success
.then(user => render(user))
.catch(err => showError(err)) // runs on an error, anywhere in the chainasync / await — the same thing, written like synchronous code
async function loadUser(id) {
try {
const res = await fetch(`/api/users/${id}`) // "pauses" the function until the response arrives
return await res.json()
} catch (error) {
return null
}
}asyncbefore the function → it always returns a Promise.await→ waits for a Promise without blocking the page (only the current function "waits").- Errors are caught with a normal
try/catch.
.then() |
async/await |
|
|---|---|---|
| Readability | chains, callbacks | top-to-bottom code |
| Errors | .catch() |
try/catch |
| When | short pipelines, outside async functions | the default |
Sequential vs parallel — the most common optimization
// ✗ sequential — the second starts after the first: 2 × the time
const user = await getUser()
const posts = await getPosts()
// ✓ parallel — both start at once
const [user, posts] = await Promise.all([getUser(), getPosts()])Go sequential only when the second request depends on the result of the first.
Promise combinators — kinds and when
| Method | Settles when | If one fails | When |
|---|---|---|---|
Promise.all |
all succeed | fails immediately | you need every result |
Promise.allSettled |
all finish | doesn't fail; you get each one's status | you want partial results |
Promise.race |
the first finishes (either way) | depends on the first | a timeout |
Promise.any |
the first succeeds | fails only if all fail | several sources, any one is fine |
Classic mistakes
forEachwithasyncdoes not wait →for...of(sequential) orPromise.all(arr.map(...))(parallel).- Forgetting
await→ you have a Promise instead of a value (user.nameisundefined). - A Promise with no
catch/try→unhandledrejection. awaitin a loop when the requests are independent → slow.
Summary
- JS has a single thread; slow operations are asynchronous so the page doesn't freeze.
- A Promise = a future value: pending → fulfilled / rejected.
async/await+try/catch;Promise.allfor parallel work.