Reputation: 16233
MDN documentation states that
When an async function is called, it returns a Promise. When the async function returns a value, the Promise will be resolved with the returned value. When the async function throws an exception or some value, the Promise will be rejected with the thrown value.
Therefore, what am I doing wrong, considering that await
expects a resolved promise?
foo();
async function foo(){
await bar();
zoo();
}
async function bar(){
setTimeout(() => {
console.log("bar");
return;
}, 1000);
}
function zoo(){
console.log("zoo");
}
According to what I (wrongly) understood, it should first log bar
and then zoo
, but it's logging the other way around.
EDIT: Now, thanks to clarifications from @Matt Morgan, I understand the mistake, as the bar()
function returns undefined
. Nonetheless, I thought that by calling an async
function per se alone would make the function return immediately an unresolved promise and that such promise would be resolved when the async
function would return any value (even undefined). But I now realise one really needs to return a promise oneself by declaring it with return Promise
statement. I think the MDN article for async
, which I read it all, is a bit confusing on this topic (just my opinion).
Therefore I could simply amend my bar()
function to:
function bar(){
return new Promise(function(resolve){
setTimeout(() => {
console.log("bar");
resolve();
}, 1000);
});
}
Upvotes: 1
Views: 1487
Reputation: 5303
bar()
is setting the timeout and returning undefined, which is not the same as immediately running the logging statement that runs when the timeout finishes.
So, zoo()
runs, and then when the timeout finishes (1000ms later), you see "bar" in the console.
Here's a modified example without the timeout:
foo();
async function foo(){
await bar();
zoo();
}
async function bar(){
console.log("bar");
}
function zoo(){
console.log("zoo");
}
With no setTimeout
, you get the order of execution you expect.
A second example, where you have a delay()
function that wraps setTimeout
in a promise:
foo();
async function foo(){
await bar();
zoo();
}
async function bar(){
await delay();
console.log("bar");
}
function delay(t, v) {
return new Promise(function(resolve) {
setTimeout(resolve.bind(null, v), t)
});
}
function zoo(){
console.log("zoo");
}
The final snippet does wait for the resolution of the promise, so you see bar
, then foo
.
The above delay
was taken from https://stackoverflow.com/a/39538518/3084820
Here's a final example, where bar()
returns "bar". This means it gets wrapped in a promise by the async
declaration, and resolved by the await
inside foo()
Again, you see what you expected to see.
foo();
async function foo(){
console.log(await bar());
zoo();
}
async function bar(){
return 'bar';
}
function zoo(){
console.log("zoo");
}
It's important to understand the your original example does not return the value bar
. It returns undefined
, and if you change your original code to log out the returned value of bar()
, you would see three things in the console:
bar()
that resolves to undefined
.zoo
from the zoo()
function.bar
logged from the setTimeout
that got shoved on the queue.Try it, see what you get.
Upvotes: 3