I have always thought that async/await
is just a syntactical sugar around Promises
and before actually executing it, JavaScript engine:
await
into .then()
catch {}
block into .catch()
finally {}
block into .finally()
But then on the MDN article about await I have read that await
pauses the execution of its surrounding
Which is a fundamentally different thing. I came up with an example of testing that.
const promise = new Promise((res, rej) => {
setTimeout(() => {
console.log('promise resolves');
res();
}, 2000);
});
async function asyncFunc() {
if (Math.random() > 0.5) {
await promise;
console.log('#1 this executes after a delay 50% times');
}
else {
console.log('#2 this executes immediately 50% times');
}
console.log('this should not wait for promise to resolve but it does');
}
asyncFunc();
The code above proofs the statement that code execution actually pauses, because if we try to translate it into the "promisified" version we will have a different code, namely the console.log
statement that was outside of if/else
statement should be duplicated in order to replicate the async/await
behavior
const promise = new Promise((res, rej) => {
setTimeout(() => {
console.log('promise resolves');
res();
}, 2000);
});
function promiseFunc() {
if (Math.random() > 0.5) {
promise.then(() => {
console.log('#1 this executes after a delay 50% times')
console.log('this code, that was outside of if/else either goes here')
})
}
else {
console.log('#2 this executes immediately 50% times');
console.log('or here, based on the result of if')
}
}
promiseFunc();
This makes me feel that Promise
and async/await
are either slightly different things, or the code translation is extremely counterintuitive.
UPD. From my point of view, an intuitive translation of the async code above should look like this.
const promise = new Promise((res, rej) => {
setTimeout(() => {
console.log('promise resolves');
res();
}, 2000);
});
function promiseFunc() {
if (Math.random() > 0.5) {
promise.then(() => {
console.log('#1 this executes after a delay 50% times')
})
}
else {
console.log('#2 this executes immediately 50% times');
}
console.log('this is outside of if/else block and should be executed regardless of await keyword above');
}
promiseFunc();
The question is:
If it actually does a pause, can we tell that async/await and promises are not the same?
No, you can't really tell the difference. The translation indeed looks more like in your second code snippet, though of course the compiler doesn't care whether it duplicates the code (or actually just references the same code twice). Notice that even as a programmer you don't have to duplicate code for conditional promise flows.
If it actually translates to Promise version before execution, why it ignores code blocks and spreads beyond them?
It doesn't ignore all code blocks. It translates them.
The full quote from MDN is actually "… pauses the execution of its surrounding async
function". It doesn't pause the execution of the if
block only.
Yes, translating control structures from await
to .then()
code is not immediately intuitive - in particular when it comes to loops or try
/catch
. But that's the entire point of async
/await
syntax - you don't have to write these complex .then()
chains any longer, and you don't need to translate anything or even think about translating it - you just use the ordinary control flow structures in asynchronous code that you're used to from synchronous code.
Whether the compiler does a complicated translation under the hood, or uses a different and more efficient execution model, doesn't matter and is not really observable.