Try the Live demo here!
While reading how Event Loop works for JavaScript & Node.js, I’ve come across this great explanation of JavaScript’s Event Loop by Philip Roberts. He had made a great visualizer called Loupe. However, I couldn’t find any similar visualizer that supports Node.js API like setImmediate() or process.nextTick().
So why not build one, I thought to myself.
Overall Architecture
Not to reinvent the wheel, The project is based on the closest visualizer I could find, js-visualizer-9000. There are two components to this project, frontend and backend. The frontend is responsible for submitting code and replaying the list of event from the backend. The frontend is pretty much complete thanks to Dillion’s work. We’ll be focusing on the backend side of the project. The core of the application is how we’re instrumenting the execution of code.
The flow of the program can be seen from the following diagram.

There are several steps required after we get the code from the frontend.
- Create New Worker using Node.js
Worker threadsAPI
- This allows running the submitted
codein an independent execution thread, preventing malicious code from crashing the server.
2. Transform Code & Inject Tracerusing Babel
- We’ll inject
Tracerto instrument function call & prevent infinite loop.
3. Run Transformed Code using vm module and async-hooks enabled
- The
vmmodule enables compiling and running of the transformed code. async-hooksis enabled to instrument flow of asynchronous function, read more here
4. Listen to Events Broadcast from worker
5. Collect & Reduce Events
- Reduce the broadcasted events into a consistent format for the frontend to replay the events
Instrumenting Execution of Code
We’re using two tools to instrument the execution flow of code:
Tracer Function
The purpose of Tracer is to broadcast event as it occurs. The event is then used by the frontend to replay and visualize the execution flow.
To use Tracer to broadcast the event, we need to inject our Tracer to call the correct method at the right place.
So how could we use the Tracer to instrument the code? The answer to this is by using plugins support from Babel.
First, we’ll transform the code submitted from the frontend into Abstract Syntax Tree(AST), then we’ll traverse the AST to look for the marker to inject our code. To understand how this is possible, read here.
Using the custom babel plugin written, the code will be transformed as shown below:
Tracer does come with a feature that will limit the loop to the time limit set by TIMEOUT_MILLIS.
Async-Hooks
By using async-hooks, we’re able to spy on the stage of an asynchronous operation, which is the whole point of this visualizer. There is a total of five hook that is supported by the API, as follow:
initbeforeafterdestroypromiseResolve
Example of the hook registered for promiseResolve as follows:
We broadcast events as it occurs by calling postEvent()
For more information on how async-hooks work, read here.
Conclusion
We’ve successfully built a visualizer for Node.js Event Loop, the live demo available here. Frontend & Backend code is pushed to Github if you would like to learn more about the implementation.
This project has been made possible by prior work from Andrew Dillon & Philip Roberts.