Node.js Design Patterns

Technical Books
In Progess
My notes & review of Node.js Design Patterns by Luciano Mammino & Mario Casciaro
Author

Tyler Hillery

Published

October 22, 2025


Notes

Chapter 2: The Module System

Loading Phases

  1. Construction (or parsing): The interpreter identifies all imports and recursively loads the content of each module from their respective files.
  2. Instantiation: For each exported entity in every module, the interpreter creates a named reference in memory, but it does not assign it a value yet. References are created for all the import and export statements to track the dependency relationships between them (liking). No JavaScript code is executed during this phase.
  3. Evaluation: The Node.js interpreter executes the code so that all the previously instantiated entities can get an actual value. Now, running the code starting from the entry point is possible because all the blanks have been filled.
  • We could say that Phase 1 is about finding all the dots, Phase 2 connects those does creating paths, and finally Phase 3 walks through the paths in the right order

    Really like this short summary of how to remember the various phases

Modules that modify other modules

This technique, where a module modifies other modules or objects in the global scope, is known as monkey patching. Monkey patching refers to the practice of altering existing objects at runtime to change or extend their behavior, or to apply temporary fixes.

The Role of the TypeScript Compiler

  • Module Loading: Will it load a TypeScript file or a pre-compiles JavaScript file?
  • Module type and module resolution: What kind of module format does the target system expected. What module type is the loaded file using?
  • Output transformation: How will the module syntax be transformed during the output process?
  • Compatibility: Can the detected module types interact correctly based on teh syntax transformation?

Chapter 3: Callbacks and Events

setImmediate() gives callbacks lower priority than process.nextTick() or event setTimeout(callback, 0). Callbacks deferred with process.nextTick() are called microtasks and they are executed just after the current operation completes, even before any other I/O event is fired. With setImmediate(), on the other hand, the execution is queued in an event loop that comes after all I/O events have been processed.

  • Node.js emits a special event called uncaughtExceptions

Observer Pattern

Reminder we have the following patterns that have been introduced

  • Reactor Pattern: The main idea behind this pattern is to have a handler associated with each I/O operation. A handler in Node.js is represented by a callback function.
  • Callback Pattern: Functions triggered to handle the result of an operation.
  • Observer Pattern: Defines an object (called subject) that can notify an observer (or listeners) when a change in state occurs.

The main difference from the Callback pattern is that the subject can notify multiple observers, while a traditional CPS (Continuation-Passing Style) callback will usually propagate its result to only one listener, the callback.

Important

What’s the difference between the Reactor Pattern and Observer Pattern?

In traditional OOP, the Observer pattern requires interfaces, concrete classes, and a hierarchy… In Node.js the Observer pattern is already built into the core and available through the EventEmitter class. The EventEmitter class allows us to register one or more functions as listeners, which will be invoked when a particular event type is fired.

TipProject Idea

Design your own EventEmitter class

When subscribing to observables with a long life span, it is extremely important that we unsubscribe our listeners once they are no longer needed. This allows us to release the memory used by the objects in a listener’s scope and prevent memory leaks. Unreleased EventEmitter listeners are the main source of memory leaks in Node.js (and JavaScript in general).

Chapter 4: Asynchronous Control Flow Patterns with Callbacks

I really like the demonstration of how to solve a race condition in spider example. Spider concurrently downloads all links that it finds on a webpage and downloads it. This can link to race condition if it finds the same link on the page twice. While the function does check if the file is already downloaded it could check that, the event loop might switch to the next function which also checks it and then both functions are now going to download the file.

The key point to solving it is right here

all we need is a variable to mutually exclude spider() tasks running on the same URL

So you can just add the url to a Set and have additional check to that this url isn’t being processed. Removing the downloaded url from the set after the file downloaded is good practice from having it grow indefinitely. The exists() will still catch other future calls to not download the file. In my head I like to think it as a way to indicate that this url is getting being processed.