So, what’s happening here? One would expect the output to flow in normal/synchronous order, start, middle and finish. But that’s not the case. Why?
code ┌────────┐ AST ┌───────────┐ Bytecode ┌──────────┐ -------> │ Parser │-------->│ Ignition │--------->│ Turbofan │---->Machinecode └────────┘ └───────────┘ └──────────┘
Now, let’s talk about why the above code runs in that order. The culprit here is
setTimeout, it’s a special function.
setTimeout is an asynchronous function call which will execute the callback function after the given
time period of
executeAfter. But the execution doesn’t wait till this is done, it moves onto the next step.
Hence the weird order, or the asynchronous order.
If it were just V8, the above code will not even work, because
and hence V8 doesn’t implement it. Also, V8 doesn’t provide any of the other asynchronous features that we normally use
execution and is similar to other languages like Python and Ruby in that regard.
So who provides the asynchronous features to Nodejs?
libuv and The Event Loop
libuv, the other major component of Nodejs. It is the asynchronous I/O engine of the Nodejs runtime
environment that provides Nodejs with necessary features to take care of I/O tasks like reading a file, network calls
and other asynchronous apis like
If you refer Event loop and nexttick you will see a diagram depicting the eventloop. I am adding below a simplified loop that I feel relevant to this discussion.
┌───────────────────────────┐ ┌─>│ timers │ │ └─────────────┬─────────────┘ Interrupts │ ┌─────────────┴─────────────┐ ┌───────────────┐ ┌──────────────────<──────────────────┤ │ poll │<─────┤ connections, │ │ │ └─────────────┬─────────────┘ │ data, etc. │ │ │ ┌─────────────┴─────────────┐ └───────────────┘ │ └──│ check │ │ └───────────────────────────┘ │ The EventLoop │ ┌───────────────────────────┐ │ │ process.nextTick │ │ └─────────────┬─────────────┘ │ ┌─────────────┴─────────────┐ └──┤ Microtasks │ └───────────────────────────┘ Not Event Loop
And the corresponding async actions that happen in each of those phases of the eventloop.
┌───────────────────────────┐ ┌─>│ setTimout,setInterval │ │ └─────────────┬─────────────┘ ┌───────────────┐ Interrupts │ ┌─────────────┴─────────────┐ │ incoming: │ ┌─────────<───────────│ │ poll and I/O callbacks │<─────┤ connections, │ │ │ └─────────────┬─────────────┘ │ data, etc. │ │ │ ┌─────────────┴─────────────┐ └───────────────┘ │ └──┤ setImmediate │ │ └───────────────────────────┘ │ The EventLoop │ ┌───────────────────────────┐ └──┤ process.nextTick │ └─────────────┬─────────────┘ ┌─────────────┴─────────────┐ │ Promise │ └───────────────────────────┘ Not Event Loop
Each phase of the event loop has its own queue. At each phase the event loop processes the queue
until it’s exhausted and moves onto the next. At each transition to the next phase it peeks outside the loop
process.nextTick queue and the micro-tasks queue. If there are callbacks in the
they are run until the queue is exhausted. Next it checks the microtasks queue, which contains the callbacks
Promises. They are run next. Only then the event loop continues with the next phase.
Please note that these two queues are not part of the eventloop.
The phases of the event loop are roughly as explained below:
1. Timers The callbacks from `setTimeout` and `setInterval` calls are executed if the respective timers are done. Note that the callbacks associated with the timers are enqueued only if the respective timer crosses the given threshold. 2. Poll The event loop polls for I/O events until its time to execute the timer callbacks. That is if any timer crosses its threshold while the loop polls for I/O, the eventloop loop backs to timer phase. If not the available I/O callbacks are executed. 3. Check Here any `setImmediate` callbacks are executed.
One more important detail to remember; the callbacks from eventloop gets executed only if the normal callstack maintained by the V8 engine for the execution of synchronous calls, is empty. This is the reason why all the synchronous calls gets executed prior to the handling of asynchronous callbacks.
If I have done a decent job of explaining the loop you should be able to predict the order of execution of the below code or at least explain it’s output.
Javascipt is synchronous. Nodejs is asynchronous because Nodejs is V8 +
all the asynchronous magic happens in
The Event Loop provided by
Well, that’s it for now! Thanks for reading my blog and I hope you got something out of it, Cheers!