77

I'm trying to learn async-await. In this code -

const myFun = () => {
    let state = false;

    setTimeout(() => {state = true}, 2000);

    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if(state) {
                resolve('State is true');
            } else {
                reject('State is false');
            }
        }, 3000);
    });
}

const getResult = async () => {
    return await myFun();
}

console.log(getResult());

why am I getting output as -

Promise { <pending> }

Instead of some value? Shouldn't the getResult() function wait for myFun() function resolve it's promise value?

1
  • 1
    async functions always return a promise. getResult is waiting for myFunc to resolve. then it returns the value in a promise. Commented Jun 15, 2021 at 20:07

6 Answers 6

50

If you're using async/await, all your calls have to use Promises or async/await. You can't just magically get an async result from a sync call.

Your final call needs to be:

getResult().then(response => console.log(response));

Or something like:

(async () => console.log(await getResult()))()
Sign up to request clarification or add additional context in comments.

8 Comments

why does last async (the one with IIFE) becomes synchronous but not my getResult() method?
@hg_git Because it's wrapped in an async IIFE, with an await call. It doesn't become synchronous, it's just syntactical sugar.
my getResult() has async keyword as well, and an await call as well..
@hg_git: async functions return promises. await "magically" unwraps a promise before the following code is executed. The code looks synchronous, but it is not executed synchronously.
This is not clear.
|
48

What you need to understand is that async/await does not make your code run synchronously, but let's you write it as if it is:

In short: The function with async in front of it is literally executed asynchronously, hence the keyword "async". And the "await" keyword wil make that line that uses it inside this async function wait for a promise during its execution. So although the line waits, the whole function is still run asynchronously, unless the caller of that function also 'awaits'...

More elaborately explained: When you put async in front of a function, what is actually does is make it return a promise with whatever that function returns inside it. The function runs asynchronously and when the return statement is executed the promise resolves the returning value.

Meaning, in your code:

const getResult = async () => {
    return await myFun();
}

The function "getResult()" will return a Promise which will resolve once it has finished executing. So the lines inside the getResult() function are run asynchronously, unless you tell the function calling getResult() to 'await' for it as well. Inside the getResult() function you may say it must await the result, which makes the execution of getResult() wait for it to resolve the promise, but the caller of getResult() will not wait unless you also tell the caller to 'await'.

So a solution would be calling either:

getResult().then(result=>{console.log(result)})

Or when using in another function you can simply use 'await' again

async function callingFunction(){
    console.log(await(getResult());
}

4 Comments

Nice explanation! You can se a running example here: codepen.io/juanmamenendez15/pen/YzPqeKj?editors=0012
@JuanmaMenendez your example does not help because a long-running process like sleep is missing!
the last example the keyword function is missing. You should write a full example, the calling of callingFunc is missing.
But you can't use await unless that function returns a promise which negates this usefulness. We could just use .then/catch for the same effect.
3

This is my routine dealing with await and async using a Promise with resolve and reject mechanism

    // step 1 create a promise inside a function
    function longwork()
    {
        p =  new Promise(function (resolve, reject) {
            result = 1111111111111 // long work here ; 

            if(result == "good"){
                resolve(result);
            }
            else
            {
                reject("error ...etc")
            } 
        })

        return p
    }

    // step 2 call that function inside an async function (I call it main)and use await before it
    async function main()
    {
         final_result = await longwork();
         //..

    }  

    //step 3 call the async function that calls the long work function
    main().catch((error)=>{console.log(error);})

Hope that saves someone valuable hours

Comments

2

What hasn't been mentioned in this discussion are the use-case implications of the behaviour. The key thing, as I see it, is to consider what you are planning to do with the output from the top level, truly asynchronous function, and where you are planning to do that.

If you are planning to consume the output immediately, i.e. within the "async" function that is awaiting the return of the top level asynchronous function, and what you do with the output has no implication for other functions deeper in the call stack, then it does not matter that the deeper functions have moved on. But if the output is needed deeper in the call stack, then you need use "async" functions making await calls all the way down the stack to that point. Once you reach a point in the call stack where the function does not care about the asynchronous output, then you can stop using async functions.

For example, in the following code, function B uses the stuff returned from function A so is declared "async" and awaits A(). Function C() calls B(), is returned a Promise, but can move straight on before that promise is resolved because it is not interested in A()'s stuff, nor what's done with it. So C does not need to be declared as async, nor await B().

function A() {
    return new Promise((resolve, reject) => {
        //do something slow
        resolve (astuff)
    }
}
async function B() {
    var bstuff = await A();
    dosomethingwith(bstuff);
    return;
}
function C() {
    B();
    dontwaitmoveon();
    ...
    return;
}

In this next example, C() does use A()'s stuff, so needs to wait for it. C() must be declared "async" and await B(). However D() does not care about A()'s stuff, nor what's done with it, so moves on once C() returns its promise.

function A() {
    return new Promise((resolve, reject) => {
        //do something slow
        resolve (astuff)
    }
}

async function B() {
    var bstuff = await A();
    dosomething();
    return bstuff;
}

async function C() {
    var cstuff = await B();
    dosomethingwith(cstuff);
    ...
    return;
}

function D() {
    C();
    dontwaitmoveon();
    ...
    return;
}

Since figuring this out, I have tried to design my code so the stuff returned by the asynchronous function is consumed as close as possible to the source.

Comments

1

BTW, await doesn't work inside of .map(), .filter(), .forEach(), etc... You have to use a plain vanilla for() loop.

3 Comments

While true, this does not appear to answer the question
It does if you're stumped (like I was) why await wasn't working inside of a .map() loop!
Omg you saved my day, I think your comment is very useful. Thx.
0

Though your "getResult" function is async and you have rightly made an await call of myFun, look at the place where you call the getResult function, it is outside any async functions so it runs synchronously.

So since getResult called from a synchronous point of view, as soon as it is called, Javascript synchronously gets whatever result is available at the moment, which is a promise.

So returns from an async function cannot be forced to await(very important), since they are synchronously tied to the place of origin of the call.

To get what you want you can run the below,

async function getResult() {
  const result = await myFun();
  console.log(result);
//see no returns here
}
getResult();

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.