I am trying to figure out how does asynchronous code work in Javascript. Now, I understand that there is actually one single thread in JS that executes jobs in a queue, and it can only start executing the next job if the current one is completed (i.e. if all of the sync code or an async function is completed).
Now, the confusing part is what actually counts as an asynchronous function - what actually gets put into a separate job in the queue, and what doesn't.
For start, we have the async keyword for functions. So does that mean those functions will be put into a separate job in the queue and be executed somewhere in the future? Well, actually it turns out the answer is NO. But bear with me, as I will explain.
As far as I understand, in theory, the JS thread is supposed to begin by executing all synchronous code until it completes, while delaying the execution of all async functions, promises and callbacks by placing them as jobs to the end of the queue. Then, once all sync code completes, it will start doing all those jobs that got piled up.
So if I have the following code:
async function asyncFunc() {
console.log("executing async function");
}
console.log("starting sync code");
asyncFunc().then(() => {
console.log("executing callback of async function")
});
console.log("sync code completed");
Then in theory, it should execute all sync code first, and only then start executing the async function and then the callback:
starting sync code
sync code completed
executing async function
executing callback of async function
But the reality is different! In reality, it actually executes the async function synchronously, together with the rest of the sync code. The only bit that actually gets put into the job queue is the callback of the async function:
starting sync code
executing async function
sync code completed
executing callback of async function
So what does that mean? That async functions are actually a lie? It seems so, as they are actually normal, synchronous functions that you can happen to attach an async callback to.
Now, I know that async is actually a syntactic sugar for a function that returns a Promise, such as:
async function asyncFunc() {
console.log("executing async function");
}
is syntactic sugar for:
function asyncFunc() {
return new Promise((resolve) => {
console.log("executing async function");
resolve();
});
}
But my point still remains. The supposedly-async function that you pass into the promise actually is executed synchronously. Well, technically the Promise object doesn't imply that it will be executed asynchronously, but the async keyword does! So it's outright false information, it makes you believe that it's asynchronous, when it demonstrably isn't.
asyncFuncis actually a synonym tofunction asyncFunc() { console.log("executing async function"); return new Promise(); }So there is no lie - it's just not doing what you thought it was.asyncfunction that never callsawait, then yes, this is no surprise. Theasync/awaitsyntax is really just that: a syntactic convenience for managing the problem of chains of.then()callback code with plain Promise objects.asyncin front of the function implies that the whole body of the function is executed asynchronously, while it isn't.async/awaitsyntax.asyncas being a sort of "type" declaration that tells JavaScript "this function returns one or more Promise objects". The parser can then build the code for the function as a generator function, with each internalawaitexpression really meaning ayieldof another Promise.