We all know that NodeJS is Single-Threaded, which means if we have an async/await operation in our code, the node will wait for it to be done before executing the rest of the code. So if a user makes an async request other users should wait for it to be done before making requests too?
Here I created a simple example, the first route uses an async function and it takes 10 sec before sending a response and the second route sends a response immediately.
When I sent a request to the first route and while waiting for a response I sent another request to the second route and I got a response even though the first route didn't finish executing the code yet.
Why is it non-blocking on this example?
function sleep(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(true)
},10000)
}).then(val=>val)
}
router.get('/route1',async (req,res)=>{
const test = await sleep()
res.send('HELLO WORLD')
})
router.get('/route2',(req,res)=>{
res.send("HELLO WORLD")
})
await only blocks/suspends execution of the current function, not the whole interpreter. In fact, at the point a function hits the first await inside the function, the function immediately returns a promise and other processing after that function (or other events that occur) are free to run.
So, in your example, when it hits the await sleep(), that function execution is suspended until the await resolves/rejects and the containing async function immediately returns an unfulfilled promise. Since Express with router.get() is not doing anything with that returned promise, it just ignores it and returns control back to the event loop. Sometime later, your second request arrives at the server, an event gets put into the nodejs event queue and Express gets called with that event and it serves your second route handler.
so if a user make an async request other users should wait for it to be done before making requests too?
No. Only that one instance of that one request handler that contains the await is suspended. Other execution in the interpreter and other event handler through the event loop (such as other incoming requests) can still happen, so other requests can still be processed, even though one request handler is sitting at an await. This illustrates how await does not block or suspend the whole interpreter, only the execution of one function.
When I sent a request to first route and while waiting for a response I sent another request to the second route and I got a response even though the first route didn't finish executing the code yet. why is it non-blocking on this example?
Only the first route was suspended by the await. Other events and other incoming requests can still be processed just fine.
NodeJs is not Single-Threaded. You can check it with these step:
Create a this js file then run it:
while(true)
On the terminal you execute this command to get the number of threads using to run this js file.
NUM=ps M <pid> | wc -l && echo number of thread is: $((NUM-1))
And you can see that while(true) uses more than 1 thread.
Let's move back to your code,
The reason why you can get the result of the request to /route2 immediately when your request to /route1 is not finished yet because NodeJs using EventLoop to make the asynchronous functions do not block the main thread.
When you call the sleep function, NodeJs will start a timer then take your callback out of the call stack(That's why the request to /route2 doesn't blocked by /route1), and when your timer is out the resolve(true) will be put in the EventQueue, and with the help of EventLoop, your callback on route1 will be executed.