Your timeTakingFunc
does all of its work synchronously, for two reasons:
- An
async
function's code is synchronous up until the first await
or return
. That's so it can start whatever process it's going to complete asynchronously.
- The executor function you pass to
new Promise
is run synchronously, running to completion before the new promise is returned to the code making the call — for the same reason that an async
function starts out synchronous. (In fact, the beginning of an async
function, before the first await
or return
, is directly analogous to the body of a promise executor function.)
So there's nothing actually asynchronous about that function.
(Side note: There's no reason to use async
on a function that never uses await
and that explicitly creates its promise. It's redundant.)
If the function had any actual asynchronous work in it that took virtually any time to complete, you'd see the order of output you expect:
async function timeTakingFunc() {
// This fetch fails, but it takes non-zero time to do so
try {
const response = await fetch("https://via.placeholder.com/150");
if (response.ok) {
await response.arrayBuffer();
}
} catch (e) {
}
}
(async () => {
try {
setTimeout(() => console.log('next task'), 0);
await timeTakingFunc();
console.log('after waiting for timetaking function');
} catch (error) {
console.log(error.message);
}
})();
But with that code, timeTakingFunc
is synchronous:
async function timeTakingFunc() {
const p = new Promise((resolve, error) => {
console.log("Start of executor function");
for (let t = 1; t < 100000; t++) {
for (let k = 1; k < 100000; k++) {}
}
console.log("End of executor function");
resolve();
});
console.log("timeTakingFunc returning promise");
return p;
};
(async () => {
try {
setTimeout(() => console.log('next task'), 0);
await timeTakingFunc();
console.log('after waiting for timetaking function');
} catch (error) {
console.log(error.message);
}
})();
...and the JavaScript engine does this:
- Sets the timer (which at some point will queue a task to run the timer callback)
- Runs the synchronous part of
timeTakingFunction
(which is all of it) to completion
- [Because of the
await
] Queues a microtask in the current task's microtask queue to run the remainder of the code
- Reaches the end of the current task
- Processes the microtask queue
- Runs the remainder of the code, logging
"after waiting for timetaking function"
- Processes the next task in the task queue, which might be the timer callback (if not, it'll show up in the queue fairly soon)
- When the timer task is run, it logs
"next task"
Which is why you see the order you see, with a synchronous function.