How to use async and await in JavaScript

Promise-returning APIs separate the moment work starts from the moment its value becomes available. async and await keep dependent JavaScript in reading order without turning the underlying operation into synchronous work.

An async function returns a new promise every time it is called. An await expression unwraps the fulfillment value inside that function and suspends only the function's continuation, so unrelated tasks can continue while the promise is pending.

A rejection at an await expression behaves like a thrown exception and can enter a nearby catch block. The .mjs module permits top-level await for the final calls; a classic browser script must keep await inside an async function or load the script with type=“module”.

Steps to use async and await in JavaScript:

  1. Create async-await-demo.mjs with a function that returns a pending promise.
    async-await-demo.mjs
    function getProfile(userId) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (userId === 0) {
            reject(new Error("profile API unavailable"));
            return;
          }
     
          resolve({ id: userId, name: "Aisha" });
        }, 100);
      });
    }

    The timer stands in for an API or file operation while preserving the same pending, fulfilled, and rejected promise states.

  2. Add an async consumer below getProfile().
    async function loadProfile(userId) {
      const profile = await getProfile(userId);
      return `Loaded ${profile.name}`;
    }

    await produces the resolved profile object at this point, while the async function exposes its eventual return value as a promise.

  3. Replace loadProfile() with a rejection-aware version.
    async function loadProfile(userId) {
      try {
        const profile = await getProfile(userId);
        return `Loaded ${profile.name}`;
      } catch (error) {
        return `Request failed: ${error.message}`;
      }
    }

    The catch branch handles a rejection from getProfile() at the await expression and converts it into the same string result shape as the fulfilled branch.

  4. Append calls that inspect the returned promise and await both result paths.
    const successfulLoad = loadProfile(42);
     
    console.log(`Returns a promise: ${successfulLoad instanceof Promise}`);
    console.log(await successfulLoad);
    console.log(await loadProfile(0));
  5. Run the completed module with Node.js to verify the promise return and both result paths.
    $ node async-await-demo.mjs
    Returns a promise: true
    Loaded Aisha
    Request failed: profile API unavailable

    The first line independently confirms the async return type, and the next two lines prove that await delivered the fulfilled value and the controlled rejection result.