TL;DR: You must await something inside the async function to make it async.
var x = 0;
async function increment(x) {
await null; // <-- ADD THIS LINE
++x;
for (var i = 0; i < 10; i = i + 1);
console.log('value of x is: ' + x);
};
increment(x);
console.log('Out of the function');
Longer version:
First let's clarify one thing: JS runtime is an event-loop based single threaded runtime, this mean no concurrency/paralell code execution (unless you use Worker or child_process, that's another topic).
Now to the asynchronous part. The async-await is just a handy syntax sugar that under the hood uses Promise and Generator, which in turn calls the event loop scheduling API provided by platfrom. In Node.js that API is process.nextTick while in browser it's setImmediate.
Through these APIs jobs are scheduled, buffered in the micro task queue, which will be tapped and executed by the event loop when idle. Thus the asynchronicity is in fact just scheduling.
With this knowledge let's come back to your case.
the async function keyword does two things:
- it forces the function to return a
Promise
- it allows you to use the
await keyword inside the function body
The actually scheduling part happens when you use the await keyword. What it does, is to send a scheduled task to the micro task queue, which will always be a callback to a Promise.then() call (in above example I send null, it'll be auto-wrapped to be Promise.resolve(null)), then pause the execution of current function, and wait until that promise resolves to continue execution of the rest.
So if you don't involve the event-loop scheduler by using await keyword, then execution order will stay normal. Thus explain your case.
If you do undertand that async function is just syntax sugar around Promise, the next often seen misunderstanding is the execution order of new Promise(callback).
Case 1:
new Promise((resolve) => {
console.log('Bob comes first!')
resolve(null)
})
console.log('Alice comes first!')
Q: Who comes first?
A: Bob comes first.
Case 2:
new Promise((resolve) => {
resolve(null)
}).then(() => console.log('Bob comes first!'))
console.log('Alice comes first!')
Q: Who comes first?
A: This time Alice comes first.
Case 1 corresponds to your code. async wrap the function into a promise's callback, but if you don't .then() that callback is executed immediately, in normal order.
Case 2 corresponds to my await null example. Which breaks up the function body into two parts, one inside new Promise(callback), the rest inside promise.then(callback). And the execution order of the latter is deferred.