DEV Community

Cover image for Simple Explanation of Async-Await in Javascript
Linda
Linda

Posted on

Simple Explanation of Async-Await in Javascript

This was orginally posted at lindaojo.com

To fully appreciate the use of Async-Await you must first understand that by default, JavaScript is synchronous.

Synchronous Functions

In synchronous functions, operations run simultaneously and you can't specify pausing or waiting points.

Example

function solveC() {
    const A = 1;

    const B = 2;

    const C = A + B;

    console.log(C);
}

solveC(); // 3

Enter fullscreen mode Exit fullscreen mode

But if for some reason there is a delay in getting the value 'B', JavaScript will execute other lines of code that aren't delayed. This could bring up unexpected results.

In the example below, 'B' is delayed using a promise. Let's check out what the results will be.

function solveC() {
    const getB = () => {
      const executor = (resolve, _reject) => {
        setTimeout(() => resolve(2), 100);
      };
      return new Promise(executor); 
    }
    const A = 1;

    const B = getB();

    const C = A + B;

    console.log(C);
}

solveC(); // "1[object Promise]"

Enter fullscreen mode Exit fullscreen mode

JavaScript logs the result before the promise above is fulfilled;

What do we do to get the right result even if B is delayed? How do we ask Javascript to pause and wait for 'B'.

The answer is we make the function asynchronous. This is where "async-await" comes in.

Note: there are other ways to write asynchronous code. You could use Callback functions and promises.

Asynchronous Functions using Async-Await

To make a function Asynchronous we declare the function using the "Async" keyword.
The word “async” before a function means the function will always returns a promise.

The async function below...

async function One() {
  return 1;
}
Enter fullscreen mode Exit fullscreen mode

is the same as the normal function below that returns a promise.

function One() {
  return Promise.resolve(1);
}
Enter fullscreen mode Exit fullscreen mode

We can ask JavaScript to wait for a promise to be fulfilled by using the "await" keyword. It has to be noted that it only makes the async function block wait and not the whole program execution.

The code block below shows how we solve our earlier problem with the use of async-await.

async function solveC() {
    const getB = () => {
      const executor = (resolve, _reject) => {
        setTimeout(() => resolve(2), 100);
      };
      return new Promise(executor); 
    }
    const A = 1;

    const B = await getB(); //waits for promise to be resolved

    const C = A + B;

    console.log(C);
}

solveC(); // 3
Enter fullscreen mode Exit fullscreen mode

Note: the "await" keyword can only be used within "async" functions.

That's it! Hope this was helpful cause I kept it light for beginners. If you want to read a more advanced explanation of async-await, I recommend this article by Ashay Mandwarya

Updated: Made a few corrections, thank you @peerreynders .

Read more of my articles

Latest comments (11)

Collapse
 
srikar9reddy profile image
srikar9reddy

Thank you so much. This was one of the best explanations.

Collapse
 
lindaojo profile image
Linda

Thank you 🥰

Collapse
 
ash_bergs profile image
Ash

Great post, it can be quite difficult to wrap your head around promises in JS, and this is a lovely primer.

Collapse
 
peerreynders profile image
peerreynders
function solveC() {
  const getB = () => {
    setTimeout(() => {return 2;}, 500); 
  }
  const A = 1;
  const B = getB();
  const C = A + B;

  return C;
}

console.log(solveC()); // NaN
Enter fullscreen mode Exit fullscreen mode

The reason solveC returns NaN is because getB will always return undefined.
And 1 + undefined is NaN.
This has nothing to do with the setTimeout.

And as it happens Promises and setTimeout are scheduled on separate queues.

setTimeout is scheduled on the task queue while promises are scheduled on the micro-task queue.

However promises are often used to get a value from setTimeout to a consumer

function solveC() {
  const getB = () => {
    const executor = (resolve, _reject) => {
      setTimeout(() => resolve(2), 500)
    };
    return new Promise(executor); 
  }
  const a = 1;
  const showC = b => {
    console.log(a + b);
  };

  getB().then(showC);
}

solveC(); // returns `undefined` but `3` displays eventually
Enter fullscreen mode Exit fullscreen mode

With async/await one can write

async function solveC() {
  const getB = () => {
    const executor = (resolve, _reject) => {
      setTimeout(() => resolve(2), 500)
    };
    return new Promise(executor); 
  }
  const a = 1;
  const b = await getB();
  console.log(a + b);
}

solveC(); // returns `Promise(<pending>)` and `3` displays eventually
Enter fullscreen mode Exit fullscreen mode

or perhaps

async function solveC() {
  const getB = () => {
    const executor = (resolve, _reject) => {
      setTimeout(() => resolve(2), 500)
    };
    return new Promise(executor); 
  }
  const a = 1;
  const b = await getB();
  return a + b;
}

solveC().then(c => console.log(c)); // Displays `3` eventually
Enter fullscreen mode Exit fullscreen mode

Resources:

Collapse
 
lindaojo profile image
Linda

I understand, thank you for the detailed correction 💙

Collapse
 
peerreynders profile image
peerreynders • Edited

Your correction

function solveC() {
    const getB = () => {
      const executor = (resolve, _reject) => {
        setTimeout(() => resolve(2), 100);
      };
      return new Promise(executor); 
    }
    const a = 1;

    const b = getB(); // b = Promise(<pending>)

    const c = a + b;  // c = 1 + Promise(<pending>)

    console.log(C);   // Displays "1[object Promise]"
}

solveC(); // returns `undefined`
Enter fullscreen mode Exit fullscreen mode

Simply replaces c = 1 + undefined with c = 1 + Promise<pending> - which similarly doesn't work.
The displayed result shows that JavaScript simply concatenated them - with really isn't useful.

Perhaps you meant:

function solveC() {
  const getB = () => {
    const executor = (resolve, _reject) => {
      setTimeout(() => resolve(2), 500); // Promise resolves to `2` here after ~500ms
    };
    return new Promise(executor);
  };
  const a = 1;
  const promiseB = getB();
  promiseB.then((b) => { // b resolves to `2`
    const c = a + b;     // c = 1 + 2
    console.log(c);      // displays `3`
  });
}

solveC(); // returns `undefined`
Enter fullscreen mode Exit fullscreen mode

This may be of interest:

Thread Thread
 
lindaojo profile image
Linda

No, that was my intention; to show what could go wrong if 'B' was delayed.

Thank you for the resources.

Thread Thread
 
peerreynders profile image
peerreynders • Edited

The point is b isn't delayed.

b is a promise, not a number.

What is delayed is the fulfillment of the promise to a number. In TypeScript this is immediately flagged as an error.

type Resolve = (v: number) => void;

function solveC() {
  const getB = () => {
    const executor = (resolve: Resolve, _reject: unknown) => {
      setTimeout(() => resolve(2), 500);
    };
    return new Promise(executor);
  };
  const a = 1;
  const b = getB();
  const c = a + b; // Error: Operator '+' cannot be applied to types '1' and Promise<number>

  console.log(c);
}
solveC();
Enter fullscreen mode Exit fullscreen mode

link

This is simply a programming error caused by type confusion

async/await doesn't "fix" this error.

async/await is simply syntax sugar so you don't have to deal with the promise directly. But await only works on promises - so you have to be aware that you are dealing with promises as it is the case with getB().

I'm not advocating the use of TypeScript here but I do think it is essential to "think in types" even when you are using a dynamically typed language.

PS: await has its own challenges:

Collapse
 
wande_sho profile image
admin.php

Nice and simple introduction. I never had a real-life use case for this, but with this explanation I can think of new ways to implement this. Thanks.

Also, I think (and I may be wrong) that you've made a mistake though.

  1. In the 3rd and 4th code blocks, the async function and the normal function both have the async keyword before them. Is that right?

  2. In the final code block, function getB( ) doesn't have the async keyword, whereas you mention that the await keyword can only be used with async functions.

Collapse
 
lindaojo profile image
Linda

Thank you, I have fixed the first issue.

Await can only be used "within" an async function. getB() does not have the async keyword because it doesn't use await within it. I hope that's clear.

Collapse
 
davidbiller profile image
David Biller

Didn’t know that it’s possible with just a setTimeout.