When async/await
used in a node.js function, will it block the node.js thread untill it executes the next line of code ?
The await operator doesn't block the thread that evaluates the async method. When the await operator suspends the enclosing async method, the control returns to the caller of the method.
Though it creates a confusion, in reality async and await will not block the JavaScript main thread. Like mentioned above they are just syntactic sugars for promise chaining.
Asynchronous MethodsWhen the executing thread reaches an await expression, it hits the “pause” button and the method execution is suspended.
await only blocks the code execution within the async function. It only makes sure that the next line is executed when the promise resolves. So, if an asynchronous activity has already started, await will not have an effect on it.
async/await
does not block the whole interpreter. node.js still runs all Javascript as single threaded and even though some code is waiting on an async/await
, other events can still run their event handlers (so node.js is not blocked). The event queue is still being serviced for other events. In fact, it will be an event that resolves a promise that will allow the await
to stop awaiting and run the following code.
Code like this:
await foo(); // foo is an async function that returns a promise console.log("hello");
is analogous to this:
foo().then(() => { console.log("hello"); });
So, await
just puts the following code in that scope into an invisible .then()
handler and everything else works pretty much the same as if it was actually written with a .then()
handler.
So, await
allows you to save the writing of the .then()
handler and gives the code a synchronous look to it (though it isn't really synchronous). In the end it's a shorthand that lets you write async code with fewer lines of code. One does need to remember though that any promise that can reject must have a try/catch somewhere around it to catch and handle that rejection.
Logically, you can think of what node.js does when it encounters an await
keyword when executing a function as the following:
async
which means that it will always return a promise.await
keyword, it suspends further execution of that function until the promise that is being awaited resolved.fn().then()
is followed by other lines of code). The .then()
handlers are not executed yet because the promise is not yet resolved.await
keyword is still suspended, but other events can be processed now.await
. If there are any more await
statements, then the function execution is again suspended until that promise resolves.return
statement or reaches the end of the function body. If there is a return xxx
statement, then the xxx
is evaluated and its result becomes the resolved value of the promise that this async
function has already returned. The function is now done executing and the promise it previously returned has been resolved..then()
handlers attached to the promise that this function previously returned to get called..then()
handlers run, the job of this async
function is finally done.So, while the whole interpreter doesn't block (other Javascript events can still be serviced), the execution of the specific async
function that contains the await
statement was suspended until the promise that was being awaited resolved. What's important to understand is step 5 above. When the first await
is hit, the function immediately returns an unresolved promise and code after this function is executed (before the promise being awaited
is resolved). It's for this reason that the whole interpreter is not blocked. Execution continues. Only the insides of one function are suspended until a promise is resolved.
async/await
provide an alternative way for what you would traditionally do with then
calls on a promise. Nor Promises, nor async
nor await
create new threads.
When await
is executed, the expression that follows it is evaluated synchronously. That expression should evaluate to a promise, but if it is not, it is wrapped into one, as if you had await Promise.resolve(expression)
.
Once that expression is evaluated, the async
function returns -- it returns a promise. Then code execution continues with whatever code follows that function call (same thread) until the call stack is empty.
At some point the promise -- that was evaluated for the await
-- will resolve. This will put a microtask in a microtask queue. When the JavaScript engine has nothing more to do in the current task, it will consume the next event in the microtask queue (FIFO). As this microtask involves a resolved promise, it will restore the previous execution state of the async
function and continue with whatever comes next after the await
.
The function may execute other await
statements, with similar behaviour, although the function now no longer returns to where it was originally called from (as that call was already processed with the first await
), it merely returns leaving the call stack empty, and leaves the JavaScript engine to process the microtask and task queues.
All this happens with the same thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With