JavaScript await: async functions, try/catch, Promise.all, top-level await

Tech reviewed: Deepak Prasad
JavaScript await: async functions, try/catch, Promise.all, top-level await

The javascript await operator waits for a Promise (or thenable) to settle and returns the fulfilled value inside an async function—or at the top level of an ES module. Pairing js await with async is the usual way to write async await javascript that reads like synchronous control flow. For how promises resolve and reject in the first place, see JavaScript Promise.resolve and JavaScript Promise.reject.

Tested on: all examples in this tutorial were run with Node.js v20.18.2, and the output shown below each snippet is its exact console output. Examples use setTimeout(..., 0) so you can reproduce results quickly; real code might use larger delays or fetch.


Quick reference

Use this table for where await javascript is valid and for picking sequential vs concurrent await patterns.

Context await allowed?
Inside async function Yes
Top level of ES module Yes
Non-async function / classic script No (SyntaxError)

Basic await promise inside async

Inside an async function, await pauses that function until the promise fulfills (or throws on rejection).

javascript
async function example() {
  const myPromise = new Promise((resolve) => {
    setTimeout(() => {
      resolve("hello world");
    }, 0);
  });
  const result = await myPromise;
  console.log(result);
}
example();
text
hello world

Two awaits in a row — sequential timing

Each await waits for its promise before the next line runs. If each delay were 2000 ms, the total would be about 4 seconds, not two—use Promise.all when the work is independent (see below).

javascript
async function sequentialExample() {
  const promise1 = new Promise((resolve) => {
    setTimeout(() => resolve("hello"), 0);
  });
  const promise2 = new Promise((resolve) => {
    setTimeout(() => resolve("world"), 0);
  });
  const result1 = await promise1;
  const result2 = await promise2;
  console.log(result1 + " " + result2);
}
sequentialExample();
text
hello world

Promise.all — concurrent await

Start independent promises first, then await Promise.all([...]) so they run concurrently and you still get ordered results in one step.

javascript
async function parallelExample() {
  const p1 = Promise.resolve("hello");
  const p2 = Promise.resolve("world");
  const [a, b] = await Promise.all([p1, p2]);
  console.log(a + " " + b);
}
parallelExample();
text
hello world

try / catch with await — rejections

Rejected promises from await propagate like thrown values inside the async function, so wrap risky awaits in try/catch (or handle with .catch on the promise).

javascript
async function mayFail() {
  try {
    await Promise.reject(new Error("bad"));
  } catch (e) {
    console.log(e.message);
  }
}
mayFail();
text
bad

await on a non-promise (await operator javascript)

Non-promise values are wrapped with Promise.resolve semantics, so await 5 still yields 5.

javascript
async function num() {
  console.log(await 5);
}
num();
text
5

Top-level await — ES modules only

Top level await javascript is allowed at module scope in ES modules. Save as a .mjs file (or set "type": "module" in package.json) and run with node:

javascript
const x = await Promise.resolve(42);
console.log(x);
text
42

In a classic script without modules, use an async IIFE instead:

javascript
(async () => {
  const x = await Promise.resolve(42);
  console.log(x);
})();
text
42

Summary

  • Use await only inside async functions or at the top level of ES modules; otherwise you get a SyntaxError.
  • Sequential await runs one settlement after another; use Promise.all (or related helpers) when tasks are independent.
  • Handle rejections with try/catch around await or explicit .catch on the promise chain.
  • await on a non-promise uses Promise.resolve semantics; top-level await needs a module context or an async IIFE in classic scripts.

References

MDN references for the await operator, async function, and concurrent waiting with Promise.all.


Frequently Asked Questions

1. Can I use javascript await outside an async function?

In a classic script or non-async function body, await is a SyntaxError. Use an async function, an async arrow IIFE, or top-level await in an ES module (.mjs or type module).

2. What does await do to a non-promise value?

The expression is converted with Promise.resolve semantics. await 5 yields 5.

3. How do I handle a rejected await promise?

Use try/catch around the await, or attach .catch to the promise chain. Uncaught rejections inside an async function reject the async function's returned promise.

4. Is sequential await the same as Promise.all?

No. await one then await another runs the second after the first settles. Promise.all runs the promises concurrently and waits for all—better when they are independent.

5. What is top level await javascript?

In ES modules, await may appear at the top level of the file. It pauses evaluation of that module for importers that depend on it. It is not supported in plain CommonJS or classic scripts.

6. Does await block the main thread?

It suspends the current async function until the promise settles, but other tasks timers and I/O can still run; it does not busy-wait the CPU.
Olorunfemi Akinlua

Boasting over five years of experience in JavaScript, specializing in technical content writing and UX design. With a keen focus on programming languages, he crafts compelling content and designs user-friendly interfaces to enhance digital …

  • JavaScript
  • Web Design