Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
World desk5 min

Mastering Async/Await in JavaScript: Practical Patterns for Modern Apps

Use async/await effectively by distinguishing dependent from independent work, selecting the right Promise combinator, propagating errors intentionally, and cancelling supported operations at their source.

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.

async and await make Promise-based code easier to read, but they do not change the underlying Promise model. Use sequential await when one operation depends on another; start independent operations together and choose a Promise combinator according to how failures and results should be handled. For errors, recover deliberately or let rejection reach the caller. For cancellation, signal the underlying operation—racing it against a timer does not stop it.

What async and await do

An async function always returns a Promise. Its returned value becomes that Promise’s fulfillment value; an exception that escapes the function makes the Promise reject. This remains true when the function returns an ordinary value rather than explicitly constructing a Promise. MDN’s async function reference describes this behavior.

await accepts a Promise, a thenable, or an ordinary value. If the awaited Promise is pending, the current async function’s continuation waits for it to settle. On fulfillment, the expression evaluates to its value; on rejection, the rejection reason is thrown at the await expression, where normal try/catch can handle it. Await does not block the main thread while the operation is pending: other JavaScript work can proceed. MDN’s await reference explains the syntax and behavior; the ECMAScript 2024 specification defines the underlying Await operation.

async function loadProfile(url) {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  return response.json();
}

This example illustrates the control flow: await the response, then return the result of parsing it. The response check is an application-level choice about what counts as success for this function.

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

Decide whether operations depend on each other

Keep dependent work sequential

If a later call needs data returned by an earlier one, await the first result before making the second call:

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

The second call needs user.id, so this is a real dependency. Starting both calls together would not provide the required input.

Start independent work together

If operations do not depend on one another, call both before awaiting their combined result:

const [profile, settings] = await Promise.all([
  getProfile(),
  getSettings(),
]);

Both calls start before the aggregate is awaited, allowing their asynchronous work to overlap. By contrast, await getProfile() followed by await getSettings() delays the second call until the first settles. This is concurrency, not parallel execution of JavaScript code: a given JavaScript thread executes one task at a time. Worker threads can provide parallel execution. See MDN’s Promise reference for the distinction and combinator behavior.

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

Put concurrency inside a branch when appropriate

Branches can use the same dependency test. Start related independent work together only in the branch that needs it; keep a call sequential if its input comes from an earlier result.

async function loadDashboard(includeSettings) {
  const user = await getUser();

  if (includeSettings) {
    const [orders, settings] = await Promise.all([
      getOrders(user.id),
      getSettings(user.id),
    ]);
    return { user, orders, settings };
  }

  const orders = await getOrders(user.id);
  return { user, orders };
}

Here, the user lookup must finish before either branch can use the user ID. Within the first branch, the orders and settings calls are independent and can be started together.

Choose a Promise combinator by its outcome policy

These methods are not interchangeable speed helpers. Choose according to whether the feature needs every operation to succeed, can use one successful result, should stop caring after the first settlement, or must inspect every outcome.

Method When the aggregate settles What it returns or does on rejection Useful when
Promise.all Fulfills after all inputs fulfill; rejects as soon as an input rejects. On fulfillment, returns values in input order. A rejection rejects the aggregate; it does not itself cancel other operations. Every result is needed and any failure should fail the overall operation.
Promise.allSettled Waits until every input settles. Returns an outcome for each input, identifying it as fulfilled or rejected. Every result or failure must be inspected, even if some operations fail.
Promise.any Fulfills when the first input fulfills; rejects if all inputs reject. On fulfillment, returns the first fulfilled value. Any one successful result is sufficient.
Promise.race Settles as soon as the first input settles, whether fulfilled or rejected. Adopts that first settlement’s value or rejection. The first result of either kind should determine the aggregate.

For example, use allSettled for independent background checks when the interface must report each check’s outcome rather than failing at the first rejection. Use all when a page cannot be considered ready without every required result. The choice is about product behavior as much as code structure.

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

Handle errors where recovery is possible

An awaited rejection behaves like a thrown error at that point in the function. Put a try/catch around the smallest region where you can meaningfully recover or add context. If there is no useful local recovery, let the async function reject so its caller can decide what to do.

async function getData() {
  try {
    return await fetchData();
  } catch (error) {
    throw new Error("Could not load data", { cause: error });
  }
}

This pattern adds context while preserving the original error as its cause. The same rejection flow can be written with .then() and .catch(); async/await changes how the control flow is expressed, not the Promise’s error-propagation model. MDN’s guide to using promises covers chain error handling and cancellation limitations.

A catch that only logs and then returns can accidentally turn a failure into a fulfilled Promise with an unusable value such as undefined. Return a deliberate fallback only when it is valid for the caller; otherwise rethrow or allow the rejection to propagate.

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

Timeouts and cancellation are different

A Promise does not provide a universal built-in cancellation protocol. Cancellation must be supported by the underlying operation. Where an API accepts a cancellation signal, an AbortController can create an AbortSignal to pass into that operation; handle an abort through the same error flow as other operation failures.

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

A timeout built with Promise.race only decides when the caller stops waiting for the aggregate result. It does not guarantee that the losing operation stops running. To stop work, cancellation must reach the underlying API through a signal or another cancellation mechanism that API supports.

Check the module context for top-level await

In ordinary scripts, await is valid inside an async function. Top-level await is available in JavaScript modules, not ordinary script context. Because this is a syntax-context distinction, a top-level await error may require changing how the file is loaded as a module or wrapping the work in an async function. Consult MDN’s await reference and async function reference for the relevant contexts.

A practical decision checklist

  • Does the next operation need the previous result? Await in sequence.
  • Are the operations independent? Start them first, then await a suitable aggregate.
  • Must every operation succeed? Consider Promise.all.
  • Must every outcome be inspected, including failures? Use Promise.allSettled.
  • Is one successful result enough? Consider Promise.any.
  • Should whichever operation settles first determine the result? Use Promise.race, but do not mistake it for cancellation.
  • Can this function actually recover from an error? Catch it locally only if recovery or useful context is possible; otherwise preserve the rejection.
  • Does the operation support cancellation? Pass its supported signal or token; a Promise alone cannot stop it.
  • Is await at file scope? Confirm the file is running as a module.

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
PC Slower Than It Used to Be?Free scan - under a minute

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.