What you'll be able to do
By the end of this page you should be able to mark a function async, await a promise, wrap awaits in try/catch, and catch the classic bug: forgetting await so you log a Promise object instead of the value.
Previous post: promise chaining.
Who this is for
- People who understand
.thenbut want code that reads top-to-bottom - Beginners about to use
fetch(next posts) - Anyone who saw
Promise { <pending> }in the console and blinked
You can skip this if async/await is already muscle memory. Come back when a missing await ships to production.
async functions return promises
async function load() {
return 42;
}
load().then(console.log); // 42
Scenario A — even sync-looking returns become promises. Callers can .then or await them.
Scenario B — throw inside async. Becomes a rejection — catch with .catch or try/catch when awaiting.
await pauses this function only
function wait(ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
}
async function run() {
console.log("start");
await wait(500);
console.log("after half second");
}
run();
console.log("run() was called — this logs before 'after'");
Scenario A — sequential steps inside run. Each await waits before the next line in that function.
Scenario B — the rest of the page. Other code still runs; await does not freeze the browser like a blocking sleep in some other languages.
try/catch with await
async function loadUser() {
try {
const value = await Promise.reject(new Error("network"));
console.log(value);
} catch (err) {
console.error("failed:", err.message);
}
}
Scenario A — replace .catch. Same idea as Blog #22 try/catch, now around async work.
Scenario B — rethrow. catch log and throw err if a parent should handle it.
Forgotten await (the #1 bug)
async function broken() {
const data = wait(10); // missing await
console.log(data); // Promise — not the resolved value
}
Scenario A — logging. You see Promise { <pending> } instead of the string/object.
Scenario B — using fields. data.name is undefined because data is still a Promise.
Fix: const data = await wait(10);
A tiny practice file
Save as async-await.html.
<!DOCTYPE html>
<html>
<body>
<button id="go">Run</button>
<pre id="out"></pre>
<script>
const out = document.getElementById("out");
function wait(ms) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve("waited " + ms + "ms");
}, ms);
});
}
document.getElementById("go").addEventListener("click", async function () {
out.textContent = "working…\n";
try {
const a = await wait(400);
out.textContent += a + "\n";
const b = await wait(400);
out.textContent += b + "\n done";
} catch (err) {
out.textContent += err.message;
}
});
</script>
</body>
</html>
Note: the click handler is async so we can await inside it.
Mistakes I see a lot
1. Forgetting await.
2. Using await outside async. Syntax error — wrap in async function or top-level await in modules (later/environment-specific).
3. Sequential awaits when work could be parallel. Fine for learning; Promise.all comes in #58 when you mean parallel.
4. Empty catch. Still log or surface the error (Blog #22 habit).
What to try before the next post
- Rewrite a three-step
.thenchain withasync/await. - Omit
awaitonce; inspect the console. - Reject a promise and catch it with
try/catch. - Build
async-await.html.
Next in this series: fetch API basics — real HTTP requests and JSON.
Try this next outside the series
Async code gets much easier when you see the same ideas on the browser side and the server side.
- Node.js async patterns — see promises and async functions in real backend flows
- Node.js streams intro — continue from simple async waits into data that arrives over time