Question:
I'm trying to understand how await
/ async
works. I have read several opinions that come to say
async
/await
is nothing more than a sugar-syntax on Promises .
However, the result I'm getting collides head -on with this: I'm not able to explain the outputs of the following code (originally taken from here ).
function sleep( ms ) {
return new Promise( resolve => setTimeout( resolve, ms ) );
}
async function demo( ) {
console.log( 'Taking a break...' );
await sleep( 2000 );
console.log( 'Two seconds later' );
}
async function demo2( ) {
console.log( 'demo2 -> before' );
await demo( );
console.log( 'demo2 -> after' );
}
function demo3( ) {
console.log( 'demo3 -> before' );
demo2( );
console.log( 'demo3 -> after' );
}
demo3( );
The result obtained is:
demo3 -> before
demo2 -> before
Taking a break…
demo3 -> after
… 2 second pause …
two seconds later
demo2 -> after
However , the expected result is this one:
demo3 -> before
demo2 -> before
Taking a break…
two seconds later
demo2 -> after
demo3 -> after
In some way I don't understand, using async
/ await
changes the order of the returns! I can't think of any way, using only callbacks and closures , that would cause that behavior.
From the outputs, it seems that the function demo3( )
returns before the function demo2( )
, which is simply impossible according to the classic execution mode that I know.
How does async
/ await
actually work? Is it really just a facility to use Promises ? Am I messing myself up looking for los 3 pies del gato
?
Answer:
I'm going to remove the syntactic sugar from your code so it's clear what's being done:
//se queda como está
function sleep( ms ) {
return new Promise( resolve => setTimeout( resolve, ms ) );
}
function demoNoSugar() {
console.log( 'Taking a break...' );
let promesa = sleep(2000);
return promesa.then(() => console.log( 'Two seconds later' ));
}
function demo2NoSugar() {
console.log( 'demo2 -> before' );
let promesa = demoNoSugar();
return promesa.then(()=> console.log( 'demo2 -> after' ));
}
function demo3NoSugar( ) {
console.log( 'demo3 -> before' );
demo2NoSugar( )
console.log( 'demo3 -> after' );
}
demo3NoSugar( );
Steps:
- Run
demo3NoSugar
, which'demo3 -> before'
. - Run
demo2NoSugar
, which'demo2 -> before'
. - Run
demoNoSugar
, which puts'Taking a break...'
into the console. - Calls
sleep(2000)
, which returns a promise that will resolve in 2 seconds. Before returning it, the order to write'Two seconds later'
when resolved is attached todemoNoSugar
. - To the resolution of that promise another command to write
'demo2 -> after'
is added todemo2NoSugar
and returned again. - We're back at
demo3NoSugar
, which doesn't catch the promise, and just ends up typing'demo3 -> after'
to the console. - The promise is resolved and the two attached messages are written.
Things to keep in mind:
A function that has an async
always returns a Promise
. Likewise, a function that returns a Promise
can be considered to be async
(and therefore can be used with await
):
async function devuelve1() {
return 1;
}
function devuelve2() {
return new Promise(res => res(2));
}
let p1 = devuelve1();
p1.then(r => console.log(r));
async function aux() {
let r = await devuelve2();
console.log(r);
}
aux();