6

I have some code using javascript async/await:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function fun1()
{
     console.log("dosomething1");
     await sleep(6000);
     console.log("dosomething2");
     return "returnfromfun1";
}
console.log(fun1());
console.log("hello");

According to the official document about async/await:

An async function can contain an await expression that pauses the execution of the async function and waits for the passed Promise's resolution, and then resumes the async function's execution and returns the resolved value.

I expect the following output:

dosomething1
//wait for 6 seconds
dosomething2
Promise { <state>: "fulfilled", <value>: "returnfromfun1" }
hello

But the actual output is:

dosomething1
Promise { <state>: "pending" }
hello
//wait for 6 seconds
dosomething2

It seems fun1 returns at the "await" line. Did I misunderstand the description in the official document? And it seems I never get the return value of fun1("returnfromfun1").

William
  • 761
  • 2
  • 10
  • 27
  • 1
    `fun1` is asynchronous, so just invoking it with `console.log(fun1());` won't wait for it to resolve - either `await` it or call `.then` on it – CertainPerformance Jul 23 '19 at 09:01
  • 3
    "According to the official document" — That's a wiki anyone can edit, not an official document. The official documentation is here: https://www.ecma-international.org/ecma-262/9.0/#sec-async-function-definitions – Quentin Jul 23 '19 at 09:02
  • asynchronous functions return promises. Calling the function returns the unresolved promise immediately, syncronously. The result of the promise can be retrieved inside a `.then()`, eg `fun1.then((result) => {})` OR by awaiting it, eg `var result = await fun1()`. – TKoL Jul 23 '19 at 09:05
  • aha,that document is too official, makes me headache even just having a peek:) – William Jul 23 '19 at 09:08
  • @JonasWilms Think so, it's very nearly the same thing - `var result = foo();` (in that other question) does not wait for the async action to complete, just like `console.log(fun1());` here does not wait for the async action to complete, though I guess there's also https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron – CertainPerformance Jul 23 '19 at 09:09
  • @certainPerformance no, disagree. `async function`s semantics are not really part of the duplicates. – Jonas Wilms Jul 23 '19 at 09:13
  • On the subject of anyone being able to edit the wiki … you might want to reread the section you quoted. – Quentin Jul 23 '19 at 09:13
  • @certainPerformance, what is the returned Promise object of fun1, the Promise object got from sleep, or another Promise object created by fun1 itself? It must not be the Promise object formed by the return value ("returnfromfun1") of fun1? – William Jul 23 '19 at 09:16
  • @william the promise returned from `sleep` resolves to nothing, wereas the promise from fun1 resolves to ` "returnfromfun1"`, therefore they have to be different. There are cases though were the engine optimizes async functions in a way that the promise awaited gets directly returned, so ut could happen. – Jonas Wilms Jul 23 '19 at 09:19

1 Answers1

3

You have to read the quoted part slightly differently:

An async function can contain an await expression that pauses the execution of the async function

Just the async function itself pauses execution, the function that called it goes on then.

If you think of a synchronous callstack, what happens is that the asynchronous functions context gets popped of, and stored somewhere else:

 stack: [init] -> [async] fun1 -> sleep -> setTimeout
  // The promise gets returned from sleep
 stack: [init] -> [async] fun1
 // The async function gets popped of
 stack: [init]
 hidden: [async] fun1
 // synchronous execution ends
 stack: -
 hidden: [async] fun1
 // the timer triggers, the promise gets resolved
 stack: setTimeout callback
 hidden: [async] fun1
 // synchronous execution ends
 stack: -
 hidden: [async] fun1
 // the promise resolves, the async fun1 context gets moved onto the stack
 stack: [async] fun1

It seems fun1 returns at the "await" line

Yes, exactly. In that moment it returns a promise, that resolves when the async function returns (after it continued execution somewhen).

And it seems I never get the return value of fun1("returnfromfun1").

You can get it when the promise resolves:

  fun1().then(result => console.log(result));
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • @JonasWilms, do you mean the Promise object returned from fun1 at await is that created in the sleep function? Can you point to an authority document that states await will return from the current async function with the Promise object created by the function following the await keyword? – William Jul 23 '19 at 09:42
  • @william no, `fun1` will create a promise internally and return that. The only "authority document" is the spec, for sure I could quote the relevant parts but I don't think that this will help you at your current stage of understanding (the spec is really, really hard to read) – Jonas Wilms Jul 23 '19 at 09:45
  • even the promise is not the one created by sleep, it must be a copy of that, right? Because the promise gets resolved after 6 seconds. – William Jul 23 '19 at 09:51
  • No. When the promise returned by `sleep()` resolves, the asynchronous function continues execution, `return`s, and internally resolves that internal promise. So they arent "copies" of each other. – Jonas Wilms Jul 23 '19 at 09:54
  • so the internal promise created by fun1 is of no use in this case,right? By the way, if we did not prepend the "async" keyword for a function name but the function returns a promise(such as sleep), the function is also an async function? – William Jul 23 '19 at 10:03
  • No it isn't `async`. Just `async function`s are async. Callbacks however behave *asynchronously*, and Promises are wrappers around callbacks, so if a function returns a promise it is very likely that it does something asynchronously. And yes, the promise returned by `fun1()` is useless if you dont use it. – Jonas Wilms Jul 23 '19 at 10:09
  • 1
    Feel much better now. Thanks a lot, JonasWilms! – William Jul 23 '19 at 10:21