73
votes

I have two functions a and b that are asynchronous, the former without await and the later with await. They both log something to the console and return undefined. After calling either of the function I log another message and look if the message is written before or after executing the body of the function.

function someMath() {
  for (let i = 0; i < 9000000; i++) { Math.sqrt(i**5) }
}

function timeout(n) {
   return new Promise(cb => setTimeout(cb, n))
}

// ------------------------------------------------- a (no await)
async function a() {
  someMath()
  console.log('in a (no await)')
}

// ---------------------------------------------------- b (await)
async function b() {
  await timeout(100)
  console.log('in b (await)')
}

clear.onclick = console.clear

aButton.onclick = function() {
  console.log('clicked on a button')
  a()
  console.log('after a (no await) call')
}

bButton.onclick = function() {
  console.log('clicked on b button')
  b()
  console.log('after b (await) call')
}
<button id="aButton">test without await (a)</button>
<button id="bButton">test with await (b)</button>
<button id="clear">clear console</button>

If you launch test without await the function seems to work as if it was synchronous. But with await, the messages are inverted as the function is executed asynchronously.

So my question is: how javascript execute async functions when no await keyword is present?


Real use case: I have an await keyword which is conditionally executed, and I need to know if the function is executed synchronously or not in order to render my element:

async function initializeComponent(stuff) {
   if (stuff === undefined)
      stuff = await getStuff()
   // initialize

   if (/* context has been blocked */)
       renderComponent() // render again if stuff had to be loaded
}

initializeComponent()
renderComponent()

P.S: title has the javascript keyword to avoid confusion with same questions in other languages (i.e Using async without await)

4
You also need to convert bButton.onclick function into an async function and await for b()to end in order to get the desired log.Jose Hermosilla Rodrigo
@JoseHermosillaRodrigo I don't want to wait for the desired log, I want to know with using or not using await keyword alters the synchronous function. And if it does not, maybe why my test is wrong. I'll update with my real use case at the end, maybe it'll be clearer for you.Ulysse BN

4 Answers

69
votes

mozilla doc:

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.

As you assumed, if no await is present the execution is not paused and your code will then be executed in a non-blocking manner.

36
votes

Everything is synchronous until a Javascript asynchronous function is executed. In using async-await await is asynchronous and everything after await is placed in event queue. Similar to .then().

To better explain take this example:

function main() {
  return new Promise( resolve => {
    console.log(3);
    resolve(4);
    console.log(5);
  });
}

async function f(){
    console.log(2);
    let r = await main();
    console.log(r);
}

console.log(1);
f();
console.log(6);

As await is asynchronous and rest all is synchronous including promise thus output is

1
2
3
5
6
// Async happened, await for main()
4

Similar behavior of main() is without promise too:

function main() {
    console.log(3);
    return 4;
}

async function f(){
    console.log(2);
    let r = await main();
    console.log(r);
}

console.log(1);
f();
console.log(5);

Output:

1
2
3
5
// Asynchronous happened, await for main()
4

Just removing await will make whole async function synchronous which it is.

function main() {
    console.log(3);
    return 4;
}

async function f(){
    console.log(2);
    let r = main();
    console.log(r);
}

console.log(1);
f();
console.log(5);

Output:

1
2
3
4
5
21
votes

The function is executed the same with or without await. What await does is automatically wait for the promise that's returned by the function to be resolved.

await timeout(1000);
more code here;

is roughly equivalent to:

timeout(1000).then(function() {
    more code here;
});

The async function declaration simply makes the function automatically return a promise that's resolved when the function returns.

7
votes

As other answers say/indicate: an async function just runs on spot until it encounters an await - if there is no await, it runs completely.

What may be worth adding that async unconditionally makes your result a Promise. So if you return something, there is a difference already and you simply can not get the result without returning to the JS engine first (similarly to event handling):

async function four(){
  console.log("  I am four");
  return 4;
}
console.log(1);
let result=four();
console.log(2,"It is not four:",result,"Is it a promise ?", result instanceof Promise);
result.then(function(x){console.log(x,"(from then)");});
console.log(3);