Async function returning before await is complete

Viewed 7934

I have two questions from the following example:

Why is does x log before y? Why is x a Promise?

I'm expecting bar to wait for foo to resolve with the value 'Hello' before it logs and then returns it.

let foo = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('Hello');
        }, 2000);
    })
}

let bar = async () => {
    let y = await foo();
    console.log(y);
    return y;
}

let x = bar();

console.log(x);

What I'm expecting to see is

'Hello' // console.log(y)
'Hello' // console.log(x)

What I'm getting is

 PromiseĀ {<pending>}  // console.log(x)
 'Hello'              // console.log(y)

Shouldn't bar wait for foo to resolve before returning y?

Any help would be much appreciated!

3 Answers

Here is the documentation about async function: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

And Promise object: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

It is stated that an async function returns a Promise object which is in a pending state until it is resolved.


Now let's look at your code:

You assign to x the return value of bar(), which is a Promise, since there is no await keyword to stop the execution (And you can not add one, because you are outside of an async function) this promise is logged as pending because the async function bar() has not yet returned.

Meanwhile, in the async function bar() you assign to y the return value of the async function foo() which is also a Promise, but this time you make it await for the result. After 2 seconds of waiting time, the promise is fulfiled and y is logged with the parameter of the resolve() method, which is Hello.

Thus the behaviour you witness is the expected one.

You need to await the function:

let example = async () => {
    let foo = () => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('Hello');
            }, 2000);
        })
    }

    let bar = async () => {
        let y = await foo();
        console.log(y);
        return y;
    }

    let x = await bar();

    console.log(x);
}

example();

You should use an await before calling bar() but, actually, you can use await just when you wrapped it by a async function like below:

async function Func() {

  let foo = () => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('Hello');
      }, 2000);
    })
  }

  let bar = async () => {
    let y = await foo();
    console.log(y);
    return y;
  }

  let x = await bar();

  console.log(x);

}

When you execute the Func(); your expectation will fire.

Related