The Node Knowledge Challenge — Part 3

Anshul Saxena
4 min readOct 30, 2022

--

This is in continuation of the famous GitHub repo node-beyond-basics. For the previous parts visit here Part 1, Part 2.

13. What’s the problem with the process uncaughtException event? How is it different than the exit event?

The uncaughtException event is emitted when an uncaught JavaScript exception bubbles all the way back to the event loop. By default, Node.js handles such exceptions by printing the stack trace to stderr and exiting with code 1, overriding any previously set process.exitCode.

Adding a handler for the uncaughtException event overrides this default behavior and the process will exit with code 0 which is clearly a problem as it signals to Node that the process is exiting without any problem. The standard advice about uncaughtException is to avoid using it, but if you must do (say to report what happened or do cleanups), you should just let the process exit anyway:

process.on(‘uncaughtException’, (err) => {// something went unhandled.// Do any cleanup and exit anyway!console.error(err); // don’t do just that!// FORCE exit the process too.process.exit(1);});

The exit event is used to end the NodeJs process, on the contrary uncaughtException is used to catch an uncaught JavaScript exception.

14. What are the 5 major steps that the require function does?

When Node invokes that require() function with a local file path as the function’s only argument, Node goes through the following five 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.

15. How can you check for the existence of a local module?

We can use require.resolve function, it will throw an error if the file doesn’t exist and will return the full path of the file once found.

function moduleAvailable(name) {try {require.resolve(name);return true;} catch(e){}return false;}if (moduleAvailable(‘module_mame’)) {// yeah we’ve got it!

16. What are circular modular dependencies in Node and how can they be avoided?

It’s better to understand circular modular dependencies using examples so let’s create two files module1.js and module2.js under lib/ and have them require each other:

lib/module1.js

exports.a = 1;require(“./module2”);exports.b = 2;exports.c = 3;

lib/module2.js

const Module1 = require(“./module1”);console.log(“Module1 is partially loaded here”, Module1);

When we execute module1.js, we see the following

node lib/module1.jsModule1 is partially loaded here { a: 1 }

We required module2 before module1 was fully loaded and since module2 required module1 while it wasn’t fully loaded, what we get from the exports object at that point is all the properties exported prior to the circular dependency. Only the a property was reported because both b and c were exported after module2 required and printed module1.

Node keeps this really simple. During the loading of a, module, it builds the exports object. You can require the module before it’s done loading and you’ll get a partial exports object with whatever was defined so far.

A circular dependency is not necessarily a bad thing and may be useful in some cases. However, if possible, it is best to avoid it as it causes bugs that are hard to reason with. Below are the two ways to deal with the problem.

1. Code Refactoring:

Circular dependency is usually the result of improper code structure/design. Code refactoring is the best way to take care of the circular dependency issue.

2. Extend exports instead of re-assigning

If a circular dependency is inevitable and introducing an intermediary is not an option, we can consider changing the way we export methods from modules to accommodate for circular references.

17. What are the 3 file extensions that will be automatically tried by the require function?

The 3 file extensions will be automatically tried by the require function are as follows:

  • .js
  • .json
  • .node

We can actually see the support of the three extensions by looking at require.extensions.

18. When creating an http server and writing a response for a request, why is the end() function required?

end()is required as it will finishes sending the request and is a medium for Node to know that request has been completed. If any parts of the body are unsent, it will flush them to the stream. If the request is chunked, this will send the terminating 0\r\n\r\n.

--

--

Anshul Saxena

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