Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
Skip to content
World desk5 min

JavaScript Promises and Async/Await Explained: A Complete Guide

A practical guide to JavaScript Promises and async/await: how values and errors flow, when to sequence work, and how to coordinate independent tasks.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A JavaScript Promise represents the eventual result or failure of an operation. async and await provide a readable way to work with Promises; they do not make asynchronous work synchronous. Understanding how values and errors move through a Promise—and when to run independent tasks together—makes asynchronous code much easier to reason about.

What is a JavaScript Promise?

A Promise is a handle for an operation whose result may arrive later. It can be in one of three states:

  • Pending: the operation has not settled yet.
  • Fulfilled: it completed successfully with a value.
  • Rejected: it failed with a reason, often an error.

Fulfilled and rejected Promises are settled: their state will not change again. Promise handlers such as .then() are scheduled by the Promise mechanism rather than invoked inline like an ordinary function call. That means attaching a handler does not make the asynchronous operation finish immediately. MDN describes Promise states and handlers.

How Promise chaining passes values and errors

Use .then() to perform the next step after a Promise fulfills. Each call to .then() returns a new Promise. The value returned by its callback becomes the next Promise’s fulfillment value; if the callback returns another Promise, the chain waits for that Promise and adopts its outcome.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For example, fetching data involves dependent steps: parse the response only after the request completes, then use the parsed data.

fetch("/api/items")
  .then((response) => {
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return response.json();
  })
  .then((items) => {
    console.log(items);
    return items;
  })
  .catch((error) => {
    console.error(error);
  });

Returning response.json() connects parsing to the chain. Without that return, the next handler would not wait for the parsing Promise or receive its result. A thrown error in a handler rejects the Promise returned by that handler, and that rejection continues down the chain until a rejection handler handles it.

.catch(handler) is shorthand for handling rejection with .then(undefined, handler). If the catch handler returns a normal value, it recovers: the Promise after .catch() fulfills with that value. If it throws an error or returns a rejected Promise, the chain remains rejected. See MDN’s guide to using Promises for the chaining and error-handling model.

How async and await work in JavaScript

An async function always returns a Promise. Returning a value fulfills that Promise with the value; an uncaught exception rejects it. Inside the function, await waits for a Promise to settle: it evaluates to the fulfillment value, or throws the rejection reason at that point in the function.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
async function loadData(url) {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  return response.json();
}

loadData("/api/items")
  .then((items) => console.log(items))
  .catch((error) => console.error(error));

loadData() returns a Promise even though its body reads like sequential code. The returned response.json() Promise determines the async function’s eventual result. The await expressions unwrap fulfilled values; if the request rejects, the error is thrown at the first await and, unless caught inside the function, rejects the Promise returned by loadData(). MDN’s async-function reference and await reference describe these behaviors.

Handling errors with try/catch

Put an await inside a try block to handle its rejection with catch:

async function showItems() {
  try {
    const items = await loadData("/api/items");
    console.log(items);
  } catch (error) {
    console.error("Could not load items:", error);
  }
}

A try/catch does not catch a Promise rejection merely because the Promise was created inside the try. The rejection must be awaited there, or the Promise must have a rejection handler such as .catch(). If you do not handle an error inside an async function, its returned Promise rejects and the caller must handle that rejection.

Promise chains or async/await?

These are two ways to express work governed by the same Promise semantics, not separate kinds of asynchronous operation. Choose the form that makes the flow and error path clearest.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Approach How flow reads Typical error handling
.then() chain Each handler returns a value or Promise for the next step. Attach .catch() to the chain or provide a rejection handler.
async/await Dependent steps read in sequence inside an async function. Use try/catch around awaited work, or handle the returned Promise at the call site.

await pauses the surrounding async function while its Promise is pending; it does not block the whole JavaScript program. Other asynchronous work can proceed. Awaiting also does not automatically start operations in parallel: the code must start independent operations before coordinating their results.

When to await sequentially and when to run tasks together

Use sequential awaits for dependent work

If the second operation needs the first one’s result, await the first before starting the second:

const user = await getUser();
const orders = await getOrdersFor(user.id);

Here, the second call depends on user.id, so the sequence is necessary.

Use Promise.all for independent work

If operations do not depend on each other’s results, start both before awaiting them:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const [first, second] = await Promise.all([getFirst(), getSecond()]);

This lets the two operations proceed concurrently. Promise.all() fulfills when every input fulfills, returning the results in input order. Its returned Promise rejects when an input rejects; it does not cancel the other underlying operations. Use it when every task must succeed for the combined result to be useful.

Choose a combinator by its completion rule

Method When its returned Promise settles Use it when
Promise.all() Fulfills when all inputs fulfill; rejects if an input rejects. Every result is needed and any failure should fail the combined operation.
Promise.allSettled() Waits for every input to settle and fulfills with each outcome. You need to inspect every success and failure.
Promise.any() Fulfills with the first fulfillment; rejects if all inputs reject. Any one successful result is enough.
Promise.race() Settles with the first input to settle, whether fulfilled or rejected. The first outcome, success or failure, should decide the result.

The distinction between any() and race() matters: any() waits for a success if an earlier input rejects, while race() follows whichever input settles first. The available Promise methods and their completion rules are listed in MDN’s Promise reference.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Where await is allowed

You can use await inside an async function. JavaScript modules also permit top-level await, so module code can wait without wrapping the statement in an async function. Ordinary script code generally needs an async function wrapper. The applicable context depends on how the JavaScript is being loaded; see MDN’s await reference.

Common Promise and async/await mistakes

  • Not returning from a .then() handler: the next step cannot depend on a value or Promise that was never connected to the chain.
  • Forgetting await: a variable may contain a Promise where the code expects its fulfilled value.
  • Expecting try/catch to catch an un-awaited rejection: await the Promise in the try block or attach a rejection handler.
  • Awaiting independent calls one after another: this serializes the waits. Start independent work first and coordinate it with an appropriate combinator.
  • Assuming Promise.all() cancels remaining tasks: its returned Promise rejects on a failure, but other operations continue unless they have their own cancellation mechanism.

When to use the Promise constructor

The executor passed to new Promise((resolve, reject) => { ... }) runs immediately when the Promise is constructed. The constructor is mainly useful for adapting an API that uses callbacks into the Promise format. It usually adds no value as a wrapper around an API that already returns a Promise. MDN demonstrates callback adaptation in its Promise constructor reference.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.