The Node Knowledge Challenge — Part 1

Anshul Saxena
5 min readOct 16, 2022

--

An inside of a complex machine showing how small parts work together

This is the first part series of answers to the famous node knowledge challenge taken from book-node-beyond basics. A huge thanks to the author Samer Buna for creating such an incredible and profound insight on NodeJs.

  1. What is the relationship between Node and V8? Can Node work without V8 ?

V8 is the JavaScript engine inside of NodeJs that parses and runs JavaScript. The same V8 engine is used inside Chrome to run JavaScript in the Chrome browser. Google open-sourced the V8 engine and the builders of the node used it to run JavaScript in the node.

No. The current node.js binary cannot work without V8. It would have no Javascript engine and thus no ability to run code which would obviously render it non-functional. Node.js was not designed to run with any other Javascript engine and, in fact, all the native code bindings that come with node.js (such as the fs module or the net module) all rely on the specific V8 interface between C++ and JavaScript. However, in 2016, there is an effort by Microsoft to allow the Chakra Javascript engine (that’s the engine in Edge) to be used with node.js. They build a V8 shim on top of Chakra so that the node.js binary code that expects to be talking to V8 can continue to do what it was doing, but actually, end up talking to the Chakra engine underneath. From what I’ve read this is particularly targeted at Microsoft platforms that already have the Chakra engine and do not have the V8 engine running on them, though presumably, you could use it on Windows too. For further information please visit the official repo for merge of chakra to NodeJS, repo and releases

2. How come when you declare a global variable in any Node file it’s not really global to all modules?

The main object exported by the require module is a function

const module_to_load = require(“path_of_file”);

When Node invokes that require() function with a local file path as the function’s only argument, Node goes through the following sequence of steps:

  1. Resolving: To find the absolute path of the file

2. Loading: To determine the type of the file content

3. Wrapping: To give the file its private scope. This is what makes both the require and module objects local to every file we require

4. Evaluating: This is what the VM eventually does with the loaded code

5. Caching: So that when we require this file again, we don’t go over all the steps another time

Because of the wrapping step, Node does not execute any code written in a file directly. It executes a wrapper function which will have the code in its body. This is what keeps the top-level variables that are defined in any module scoped to that module.

The wrapper function can be inspect using the wrapper property of the module module

> ~ $ node> require (‘module’).wrapper> [ ‘(function (exports, require, module, __filename, __dirname}) { ‘,\> ‘\n});’

3. When exporting the API of a Node module, why can we sometimes use exports and other times we have to use module.exports?

exports variable inside each module is just a reference to module.exports which manages the exported properties. When we reassign the exports variable, that reference is lost and we would be introducing a new variable instead of changing the module.exports object. Hence we can change the value of properties inside exports object , so assignments which doesn’t change the object can be safely performed using the `exports`. for e.g:

exports.id = “some_value”;

whereas for reassignments we have to use module.exports

module.exports = function() {};

4. What is the Call Stack? Is it part of V8?

The Call Stack is definitely part of V8. It is the data structure that V8 uses to keep track of function invocations. Every time we invoke a function, V8 places a reference to that function on the call stack and it keeps doing so for each nested invocation of other functions. This also includes functions that call themselves recursively.

When the nested invocations of functions reaches an end, V8 will pop one function at a time and use its returned value in its place.

Why is this important to understand for Node? Because you only get ONE Call Stack per Node process. If you keep that Call Stack busy, your whole Node process is busy. Keep that in mind.

5. What is the Event Loop? Is it part of V8?

The event loop is provided by the libuv library. It is not part of V8.

The Event Loop is the entity that handles external events and converts them into callback invocations. It is a loop that picks events from the event queues and pushes their callbacks into the Call Stack. It is also a multi-phase loop.

The Event Loop is part of a bigger picture that you need to understand first in order to understand the Event Loop. You need to understand the role of V8, know about the Node APIs, and know how things get queued to be executed by V8.

The Event Loop sits in the middle between V8’s Call Stack and the different phases and callback queues and it acts like an organizer. When the V8 Call Stack is empty, the event loop can decide what to execute next.

6. What is the difference between setImmediate and process.nextTick ?

NodeJs offers many options to postpone code execution until later. Two of these, setImmediate and process.nextTick, are similar in the way that they make the code run soon.

So, process.nextTick is used when we want to effectively queue the function at the head of the event queue so that it executes immediately after the current function completes i.e. callbacks passed to process.nextTick will usually be called at the end of the current flow of execution, and are thus approximately as fast as calling a function synchronously. Left unchecked, this would starve the event loop, preventing any I/O from occurring whereas setImmediate is used to queue the function behind whatever I/O event callbacks that are already in the event queue so they are queued in the order created, and are popped off the queue once per loop iteration.

So in a case when you are trying to break up a long-running, CPU-bound job using recursion you would want to use setImmediate rather than process.nextTick to queue the next iteration as otherwise any I/O event callbacks wouldn’t get the chance to run between iterations.

--

--

Anshul Saxena

Writing code and building systems that help people to improve their lives 🔋, loves JavaScript ✨