
Install node and npm on your machine, preferably the latest node version, with Node.js 18 as the minimum, and use VSCode; bring at least one year of Node.js project experience.
Explore the course structure and key topics, including Node.js design patterns, the streams API, and performance strategies.
Explore creational design patterns in JavaScript and Node.js, including factory, singleton, builder, and revealing constructor patterns, and learn how dependency injection structures module and object connections.
Explore the singleton pattern in Node.js, a widely used object-oriented design pattern, and address issues in a code example by applying the singleton pattern.
Explore the singleton pattern to guarantee one logger instance across product and customer classes, preventing duplicate logs. See how to migrate from require to import and implement the logger singleton.
Implement a singleton pattern to fix a logger issue: create a Singleton class with an instance getter, share one logger across files, and verify with tests.
Explore a simpler, more typical way to implement the singleton pattern in Node.js by exporting a single logger instance through a module.
The singleton pattern provides a shared instance to share state and avoid expensive objects like a database connection pool or logger, while Node.js module caching may yield instances across versions.
Learn how the prototype pattern in node.js uses a base object to clone default items for new customers, reducing code duplication and improving readability.
Apply the factory pattern to create objects via a factory function, instead of new, separating creation from usage and using closures to keep data private.
Learn to implement the factory pattern to encapsulate object creation, allowing a single person factory to return the correct subclass (customer or employee) based on input.
Explore the builder pattern to construct complex objects step by step, avoiding messy multi-argument constructors, enabling fluent interfaces and safe, readable object creation.
Demonstrates how the builder pattern clarifies object creation with a person builder and methods like make employee and make manager, culminating in a build call.
Learn to implement the builder pattern in Node.js by creating a person builder that constructs a customer via chaining methods and a final build step to improve readability.
Learn the revealing constructor pattern in Node.js to create immutable objects by exposing members during initialization, keeping internals private, with a constructor, executor, and revealed members.
Master revealing constructor pattern by building a config class with a configurator to set values and set multiple, freeze the settings for immutability, and expose get and getAll as read-only.
Learn how dependency injection reduces tight coupling by passing dependencies, such as a database, from an external source via the constructor, making code more modular and testable.
Celebrate finishing the first section on classic design patterns for creating objects and their reuse in Node.js applications. Explore structural patterns that organize objects for flexible, reusable structures.
Explore how the adapter pattern bridges browser local storage to Node.js by providing a compatible interface with getItem, setItem, and length to enable cross-environment data access.
Explore the adapter pattern by recreating the browser local storage API in node.js, using a json file and fs to implement get item, set item, and length with memory loading.
Explore the proxy pattern in Node.js, wrapping a file system object to control access, enabling security checks, logging, or caching, and restricting reads to txt files.
Demonstrates the proxy pattern with an fs proxy that restricts reads to txt files, preserving the original fs interface while delegating valid calls.
Explore the composite pattern, a structural design pattern that lets you treat individual objects and compositions uniformly in tree-like hierarchies, such as files and folders with a get size method.
Implement the composite pattern by building a product category that aggregates products and subcategories, computes the total with reduce, and prints details uniformly for leaves and composites.
Explore the decorator pattern in Node.js by decorating a base phone case with silver and gold features, enabling flexible composition without creating separate classes.
Implement the decorator pattern by adding silver and gold item decorators that wrap a base item, update names and prices, extend fields like waterproof, and demonstrate decorated purchases.
Explore the chain of responsibility design pattern through a Node.js example, linking basic, technical, and manager handlers with set next and handle to process requests or leave unhandled.
Implement the chain of responsibility by building a handler class with setnext and handle, wiring basic, technical, and manager supports into a chain that passes requests until handled or unhandled.
Explain the command pattern with a remote control analogy, where an invoker triggers commands without details, enabling undo, redo, and queued execution through a receiver and command classes.
Implement the command pattern by building exit and create commands, a singleton receiver, and a file-creation workflow, driven by an invoker that runs and logs commands.
Dive into the command pattern to enable traceability and undo/redo, with a receiver that records command history and supports create, undo, redo, and trace logging.
Learn the iterator pattern to traverse any collection with a simple next, previous, first, and last interface, isolating iteration logic for cleaner, more maintainable code.
Implement the iterator pattern by building a class with next, prev, first, last, hasNext, and current to traverse a collection; default to an empty array and track the index.
Learn the observer pattern by modeling a weather station as the observable and devices as observers, implementing add observer and set temperature to notify subscribers on state changes.
Implement the observer pattern by building a weather station as an observable subject, managing observers, and notifying them on temperature updates.
Explore the strategy pattern by modeling payment methods as strategies. Include credit card, PayPal, and bank transfer, and wire them into a flexible processor using set strategy and process payment.
Implement the strategy pattern in a payment processor by setting a strategy, delegating payments to PayPal, credit card, or bank transfer, and validating strategy presence.
Explore the state pattern by contrasting it with the strategy pattern, enabling an object to switch between online and offline behaviors in a chat client, with transitions and message queuing.
Implement the state pattern in a Node.js WebSocket client using ws, modeling offline and online states, queuing messages offline, and retry-based state transitions.
Master the template design pattern as a blueprint for fixed steps and customizable parts. Implement abstract parse and stringify in JSON and YAML config managers to load and save configurations.
Explore how to handle asynchronous initialization in Node.js components, using readiness checks, startup sequencing, and the state pattern to queue calls until a component is ready.
Learn how to ensure a message service is ready before use by locally checking initialization and authentication, awaiting readiness, and then sending messages.
Delay app startup with an async init that waits for authentication via a message service and an event emitter; once authenticated, proceed to notify user, highlighting timing and reinitialization drawbacks.
Apply the command pattern to manage asynchronous initialization by queuing messages until authentication completes, using a promise-based command queue and an event emitter.
Master the state pattern in Node.js by implementing a queuing state for commands until authentication completes, then switch to a ready state to execute, reducing boilerplate.
Delve into the Node.js event loop with concise visuals and diagrams in a short theoretical section of up to five lessons. Rewatch if needed and use QA support.
Explore how the node and browser event loops convert external events into callbacks, moving them between the event queue and the call stack, with notes on stack, heap, and libuv.
Explore how the V8 call stack tracks function calls in a single-threaded JavaScript runtime, linking stack frames, recursion, and error traces.
Learn how slow, expensive operations block the Node.js call stack and how the event loop prevents blocking programming, highlighting blocking versus non-blocking approaches and V8 behavior.
Explore how the node API relies on callbacks, illustrating setTimeout timers, the call stack, and the event loop to show asynchronous, non-blocking behavior.
Explore how setTimeout, setImmediate, and process.nextTick schedule tasks in Node.js, showing that zero delays wait for the call stack to clear and vary by event loop phase.
Understand how NodeJS uses a single thread to enable asynchronous patterns with callbacks. Compare direct and continuation passing style, cover error-first callbacks, and introduce process.nextTick and setTimeout for async flow.
Explore continuation-passing style (CPS) in JavaScript, showing how callbacks transfer results to functions, use closures to preserve context, and let the event loop run other tasks during async work.
Ensure API consistency by using either fully asynchronous or fully synchronous patterns, avoiding mixed sync/async calls that cause hard-to-find bugs, as shown with a cache fetch example.
Follow the Node.js error-first callback pattern by placing the callback last and passing errors as the first argument, and wrap synchronous code in try/catch to propagate errors via the callback.
Explore the observer pattern in Node.js by building an event emitter-driven CSV search that registers listeners for file read and record found events, handles errors, and contrasts with callbacks.
Convert the csv searcher from direct event emitter usage into a class that extends event emitter. This encapsulates logic and enables observers to subscribe via on and react with emit.
In Node.js, adding a listener with emitter.on can keep large objects in memory via its closure, causing a memory leak unless you unregister unused listeners with removeListener or off.
Emphasize consistent events by emitting all related events either synchronously or asynchronously within a single control flow, avoiding mixed modes in the event loop.
Choose callbacks for single-result operations and simple readability, and use event emitters for multiple outcomes or repeated events with multiple listeners.
Explore combining callbacks with an event emitter to receive a final result and real time progress from a single asynchronous operation, illustrated by a scan folder example and error handling.
Explore promises in node.js to replace callbacks with then chains for managing asynchronous tasks, using resolve and reject. See how delay and setTimeout illustrate promise chaining and avoid callback hell.
Explore how to reject promises intentionally, handle errors with catch, read error messages, and use explicit rejects to control failure scenarios in asynchronous code.
Convert callback-based asynchronous functions to promises using Node.js util.promisify, transforming error-first callbacks into promise-based calls and enabling concise code with then and catch for fs operations.
Master sequential execution in Node.js by replacing callback hell with promisified fs operations and a custom wait function, then chain promises for clean, maintainable code.
Learn how to replace promise chains with async/await to run tasks sequentially, including handling promises, try-catch, and promisified I/O like read dir and write file.
Explore parallel execution of promises in Node.js, using Promise.all and Promise.race to run multiple file operations in parallel and handle results efficiently.
Run multiple promises in concurrent style with a promise queue that limits parallel tasks; manage to-do, running, and done lists using run, then, finally.
Log concurrent tasks in a node.js promise queue with log-update to keep a single, live terminal log and visualize to-do, running, and done lists.
Compare buffer transfers and streams in Node.js to understand memory use and performance. Streams read files bit by bit to avoid memory leaks and discuss garbage collection basics.
Learn to work with readable streams in Node.js by implementing a custom array-based readable stream, handling data and end events, and exploring binary, string, and object modes.
Explore using readable streams in node by reading a file with fs.createReadStream, handling data, end, and error events, and switching between flowing and non-flowing modes via pause, read, and resume.
Read from a read stream and write to a writable stream to copy an mp4 file, chunk by chunk, ending the write when the read stream ends.
Learn backpressure in Node.js streams by detecting full writable streams, pausing the readable stream, and resuming on the drain event, with high water mark to handle more data.
learn how piping streams connects a readable stream to a writable stream using the pipe method, which automatically handles back pressure and errors, demonstrated with stdin to test.txt.
Duplex streams in Node.js enable bidirectional pipelines by sitting between a readable and a writable stream, allowing reporting or throttling while piping data without altering chunks.
Delve into transform streams in node.js, a duplex stream that alters data on read. Build ChangeText to replace characters with a symbol using regex, then test via stdin and stdout.
Build a small node.js web server to stream an mp4 video to a browser using streams and HTTP headers, creating a read stream and promisified fs.stat for content-length.
Learn to implement range requests in a Node.js server to stream video portions by parsing the range header and returning partial content with a 206 status.
Stream a file from client to server using the http request as a readable stream and the http response as a writable stream, including video routing and multipart uploads.
Install the multi-party npm package and parse multipart form data from the request. Stream each part through a readable stream into a server write stream, handling file uploads efficiently.
Build a real-time chat app with Node.js streams and the net module, connecting multiple clients to a single server and broadcasting messages via custom writable and duplex streams.
Create a simple chat server and client using Node's net module, piping a duplex circuit between server and clients, with server listening on port 3000 and clients connecting to localhost.
Listen to new client connections, assign a unique id with random uuid, track clients in a map, broadcast messages to all except the sender, and log disconnects.
Learn to build a custom client side writable stream in Node.js that overrides the write function, processes server chunks, and prints id and messages to the terminal.
Use a custom writable stream to broadcast messages to all connected clients except the sender, wiring a server side stream to distribute data via the client circuits.
Welcome to this course, designed for those who aspire to become Node.js experts.
This course is designed to introduce you to more intermediate-advanced topics in Node.js, including internals, streams, design patterns, and scalability. The content of this course was made for you who want to become a Node.js expert.
In this course I avoided long-winded fluffy projects full of configurations and third-party tools that quickly become outdated. Instead, you’ll find concise, focused lessons that help you level up your Node.js skills and deepen your understanding of the Node.js .
The current version of the course consists of 3 + 1 main modules.
1. Design Patterns:
In the Design Patterns module, we explore the most common design patterns in the context of Node.js. For each pattern, we begin with a simple example that highlights a problem, and then we solve it using the appropriate design pattern. This approach not only introduces you to design pattern concepts but also shows where and how to apply them effectively.
2. Asynchronous Programming Fundamentals:
In this module, you’ll learn advanced techniques for managing asynchronous programming and data streaming in Node.js. We’ll cover asynchronous patterns such as callbacks, promises, and async/await, and how to apply them for sequential, parallel, and concurrent execution.
The course is beginner-friendly so this module covers the fundamentals. You might already be familiar with some of the material in this module, but I highly recommend going through it, as I’ve structured the course progressively, starting from the basics of Node.js and building up to the Streams API. However, you can skip any part since the lessons are not tightly dependent on one another.
3. Streams API
The third module focuses on the Streams API. First, we explore the traditional API, then dive into the more modern API, giving you a comprehensive understanding of both. I also provide a practical example to help you better grasp when and how to use the Streams API.
4. Performance and Scaling Node.js Applications:
In the performance module, I start by walking you through the fundamental concepts of scalability in Node.js, including forking an application into multiple child processes and multi-threading with process pools. In the second section, we revisit the Streams API, but this time we combine it with child processes to handle time-consuming operations more efficiently.
Note: Several additional modules and sections will be added to the course in the coming weeks.