javascript – Incorrect sequence of returns using async / await

Question:

I am trying to understand how await / async . I have read several opinions that come to say

async / await is nothing more than a syntax-sugar on Promises .

However, the result I am getting clashes head-on with this: I am 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 other:

demo3 -> before
demo2 -> before
Taking a break …
Two seconds later
demo2 -> after
demo3 -> after

Somehow that I don't understand, the use of 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 demo3( ) function returns before the demo2( ) function, which is simply impossible according to the classic execution mode that I know.

How does async / await really await ? Is it really just an ease to use Promises ? Am I messing around looking for los 3 pies del gato ?

Answer:

I'm going to remove the syntactic sugar from your code so that it is clear what is 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:

  1. Run demo3NoSugar , which puts 'demo3 -> before' in the console.
  2. Execute demo2NoSugar , which puts in console 'demo2 -> before' .
  3. Run demoNoSugar , which says 'Taking a break...' .
  4. Run sleep(2000) , which returns a promise that will resolve in 2 seconds. Before returning it, the command to write 'Two seconds later' is attached to demoNoSugar when solved.
  5. To the resolution of that promise, another command is added to write 'demo2 -> after' in demo2NoSugar and it is returned again.
  6. We are back in demo3NoSugar , which doesn't capture the promise, and just ends up typing 'demo3 -> after' in the console.
  7. 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();
Scroll to Top