JAVASCRIPT / LESSON 18

Read asynchronous steps with async and await

Await promise results and recover with try, catch, and finally.

Content updated

By the end, you can…

  • await pauses the current async function until a promise settles; the rest of the page can continue.
  • Predict the example's result, change one part, and verify the behavior in your own script.
Before you begin

One idea at a time

async and await provide another way to write promise-based code. An async function always returns a promise, even when it returns an ordinary number. Inside that function, await gives you a fulfilled result or throws the rejection reason. It makes a sequence easier to read without changing the underlying promise behavior.

Pausing the function is different from blocking the entire browser. Other work can continue while a promise is pending. However, a long synchronous calculation inside an async function still blocks while it executes. Adding async to a function is not a tool for making expensive CPU work run in parallel.

What to remember first

Remember first

await pauses the current async function until a promise settles; the rest of the page can continue.

Read the code before trying it

async function load()Declare a promise-returning function
Calling load returns a promise immediately. Code inside runs until it reaches an await or finishes.
const value = await promiseReceive a future result
Use await inside an async function in these classic scripts. Modules have additional top-level await rules.
try / catchHandle a rejected await
A rejection at await behaves like a throw inside try, transferring control to catch.
finallyRestore state either way
Cleanup runs after success, failure, and returns inside try. It is useful for re-enabling a button.
await Promise.all([...])Wait for independent work together
Use this when neither operation needs the other's result; sequential awaits are appropriate for dependent steps.

Walk through an example

javascript
async function showCount() {
  console.log("Start function");
  try {
    const count = await Promise.resolve(3);
    console.log(count);
  } catch {
    console.log("Could not load count");
  } finally {
    console.log("Cleanup");
  }
}
showCount();
console.log("Outside function continues");

showCount starts and logs its first message. At await, it suspends even though this promise is already fulfilled. The outer script logs Outside function continues. The function then resumes with 3 and runs cleanup. Compare the output order before assuming await behaves like a blocking sleep.

See it happen: try a small change

Read asynchronous steps with async and await: try it

Predict the result, choose a version, then compare the code and output. Try the controls when the example has them. Each version starts fresh.

Code to notice

async function run() {
  console.log("Loading");
  try {
    const value = await Promise.resolve(3);
    console.log(value);
  } catch {
    console.log("Try again");
  } finally {
    console.log("Ready for another attempt");
  }
}
run();
console.log("Outer code continues");

Live result

Lesson example
index.htmlPreview

What changed: await yields before logging three. finally runs after success too.

Look a little closer

An async return value is wrapped in a promise. If you need the value from a call, await it in another async function or use then. Catch errors where your program can recover. A function that throws without a local catch returns a rejected promise to its caller, so the caller must handle that failure.

For UI code, plan all states before writing the request: idle, loading, success, and failure. Set loading before await, show success or failure afterward, and restore the disabled control in finally. This structure prevents an error from trapping the user behind a permanently disabled button.

Try it in your own project

Replace the previous chain with one async function, call it, and put an outside log after the call. Compare success and rejection. Keep await inside try so catch handles that rejection locally.

The interactive preview runs in its own isolated document. Its Output panel mirrors console.log messages; it is not a full DevTools console. Choosing another version or resetting starts a fresh example and does not edit your local files. Read any simulation label: storage and request demonstrations explain their offline substitutes, while the written local examples use the real browser APIs.

A common wrong turn

A try/catch does not catch a promise’s later rejection merely because that promise was created or returned inside try. Await it inside try to catch the rejection there; returning it without await leaves rejection handling to the caller. Put await inside try, or attach a catch to the promise. Also avoid awaiting independent operations one by one when they can safely start together; first decide whether there is a real dependency.

Your turn: read asynchronous steps with async and await

Rewrite the previous lesson's promise chain as an async function with visible cleanup.

Try this in your own HTML and JavaScript files, then open the page in a browser. There is no separate checked practice for this task yet.

  1. Await a resolved value inside try and log its doubled result.
  2. Replace it with a rejected promise and show a fallback from catch.
  3. Log cleanup in finally and verify it appears in both runs. Add an outside log and explain its position.

Go to the source

Examples are authored for Tuklas and checked with code and reference documentation. This is not a claim of independent human review. Suggest a correction.