Execute Program

JavaScript Concurrency: Multiple Awaits

Welcome to the Multiple Awaits lesson!

This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!

  • Async functions can contain more than one await. Here's a delayed double function that we'll use in our examples. (Remember that async functions return promises!)

  • >
    const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
    function double(n) {
    return sleep(500).then(() => 2 * n);
    }
  • We can call double three times by assigning each result to a new variable.

  • Note: this code example reuses elements (variables, etc.) defined in earlier examples.
    >
    async function octuple(n) {
    const doubled = await double(n);
    const quadrupled = await double(doubled);
    const octupled = await double(quadrupled);
    return octupled;
    }

    octuple(3);
    Asynchronous Icon Async Result:
    {fulfilled: 24}Pass Icon
  • We can also collapse those calls into a single line of code. Either form may be preferable depending on the situation. With async/await, we can choose between them, whereas regular promises force us to use then chains.

  • Note: this code example reuses elements (variables, etc.) defined in earlier examples.
    >
    async function octuple(n) {
    return await double(await double(await double(n)));
    }

    octuple(3);
    Asynchronous Icon Async Result:
    {fulfilled: 24}Pass Icon
  • Under the hood, each await will call then, effectively pausing the function at that point. If we rewrite the code to show that explicitly, it becomes more complex and more difficult to read. But it shows us that async/await is only "syntactic sugar": it's a nicer-looking syntax for creating promises, even though we can always create them the old way too.

  • Here's a closer look into how our octuple function works. We have to introduce some temporary variables, prefixed with _ to distinguish them.

  • Note: this code example reuses elements (variables, etc.) defined in earlier examples.
    >
    function octuple(n) {
    const _temp1 = double(n);
    return _temp1.then(_temp2 => {
    return double(_temp2).then(_temp3 => {
    return double(_temp3);
    });
    });
    }

    octuple(3);
    Asynchronous Icon Async Result:
    {fulfilled: 24}Pass Icon
  • In this case, we could also write a nice equivalent with promises: return double(3).then(double).then(double). However, most real-world async/await code doesn't convert into promises so nicely. Often, async/await can turn ugly nested promise code like the example above into clean-looking function calls.

  • Here's a code problem:

    Complete this addSix function. It should add 6 to its argument. But it should do that by calling the addTwo function three times. (Remember, we can only use await within an async function!)

    async function addTwo(n) {
    return Promise.resolve(n + 2);
    }

    async function addSix(n) {
    return await addTwo(await addTwo(await addTwo(n)));
    }
    Promise.all([addSix(3), addSix(7)]);
    Asynchronous Icon Async Result:
    Goal:
    {fulfilled: [9, 13]}
    Yours:
    {fulfilled: [9, 13]}Pass Icon