JavaScript runs on one thread — it can't stop and wait, or the whole page freezes. Async code is how it starts slow work (network, timers) and reacts when results arrive.
A Promise is a placeholder for a future value. Modern code consumes them with async/await: inside an async function, await promise pauses that function (not the page!) until the value arrives. Wrap awaits in try/catch for errors.
console.log("1: start");
setTimeout(() => {
console.log("3: after 2s (page never froze)");
}, 2000);
console.log("2: this runs IMMEDIATELY");
// JS never blocks — it schedules and moves onconst delay = (ms) =>
new Promise(resolve => setTimeout(resolve, ms));
delay(1000)
.then(() => console.log("1 second later"))
.then(() => delay(1000))
.then(() => console.log("2 seconds — chained!"))
.catch(err => console.error("something failed:", err));async function loadUser(id) {
const res = await fetch(`/api/users/${id}`); // pause HERE
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const user = await res.json();
return user; // async fns always return a promise
}
// consuming it:
const user = await loadUser(1); // top-level await (modules)
console.log(user.name);async function safeLoad() {
try {
const data = await loadUser(1);
render(data);
} catch (err) {
console.error("load failed:", err.message);
showRetryButton();
} finally {
hideSpinner(); // runs either way
}
}// sequential — slow (one after another):
const a = await fetchA();
const b = await fetchB();
// parallel — fast (both at once):
const [resA, resB] = await Promise.all([fetchA(), fetchB()]);
// don't want one failure to kill both?
const results = await Promise.allSettled([fetchA(), fetchB()]);
// [{status:"fulfilled", value}, {status:"rejected", reason}]console.log(loadUser()) prints Promise {<pending>}An IOU for a value that isn't ready yet — it's pending, then either fulfills with a value or rejects with an error, and you attach code to run in each case.
No — it pauses only that async function. The browser keeps handling clicks and rendering while the awaited work completes.
They're the same machinery; async/await reads like normal code and plays better with try/catch and loops, so it's the modern default.
all rejects immediately if ANY promise fails; allSettled always waits for every promise and reports each outcome.