
Explore advanced Node.js concepts from operating system basics to non-blocking I/O, child processes, cluster, and worker threads, and grasp race conditions shaping web app performance.
Explore the basic concepts of the operating system and understand why this foundational section is essential for backend developers advancing in Node.js.
Learn how hardware and software interact as the CPU executes programs by loading them from the hard disk into RAM, which is fast but not permanent.
Understand the difference between a program and a process, and how the cpu moves data from hard disk to ram, transitioning through ready, running, and io states.
Explore multiprogramming and multiprocessing, showing how a single CPU executes one task at a time, and how context switching enables concurrency in memory.
Explore how the CPU executes processes by contrasting non-preemptive and preemptive scheduling, illustrating how the CPU can switch between tasks like games and applications.
Understand how the program counter orchestrates line-by-line execution, how the central processing unit advances through machine code in random access memory, and why memorizing the last program counter underpins synchronization.
Learn context switching by storing the current project's information, including the program counter, when moving to another process and preserving the stack and heap state.
Explore how JavaScript, a high-level language, reaches the CPU through the V8 JavaScript engine by translating code into machine code the processor can execute.
Explore how normal compilers, interpreters, and just-in-time (JIT) compilers convert code to machine code, with JIT optimizing repeated execution for faster performance.
Introduce libuv as the C++ libraries behind Node.js's non-blocking I/O, the event loop, and the thread pool to enable asynchronous operations.
Learn how Node.js executes JavaScript: the V8 engine compiles code, while the core Node API delegates asynchronous file I/O such as fs.readFile to libuv and operating system via C++ bindings.
Explain CPU tasks versus IO tasks in node.js, showing how heavy calculations consume CPU cycles while file reads and other IO operations delegate to the OS and wait.
Node.js delegates a client request from the V8 engine to the Node API, then to a library and the operating system through the event loop using non-blocking I/O.
Understand how Node.js leverages the event loop and a thread pool to handle CPU tasks, while the OS forbids non-blocking IO for file systems, requiring simulated async behavior for fetch.
Learn how a thread pool offloads heavy crypto tasks from the main thread, preventing blocking and enabling limited concurrent requests during CPU-bound operations.
Demonstrate a crypto function from the Node.js core module as a cpu-intensive task and its blocking of parallel requests. Preview worker threads to move cpu work off the main thread.
Explore native non-blocking I/O in node.js, demonstrating how the operating system allows many simultaneous requests using minimal threads. See how non-blocking tasks scale beyond traditional threads in practice.
Compare blocking IO and thread-based handling in traditional web apps with non-blocking IO in Node.js. See how Java Spring's thread pool contrasts with Node.js's non-blocking model in handling multiple requests.
Discover how the Node.js event loop, powered by Libuv, coordinates synchronous code, micro tasks like promises, callbacks, and timeouts through the call stack and API-driven event queue.
Explore the concept of a child process in Node.js, showing how a parent forks a server process, manages ports, and tracks process arrays and IDs.
Learn how the cluster module lets Node.js run multiple server instances across CPU cores, improving performance by avoiding the blocking Fibonacci workload compared to the fast route.
Learn how to leverage Node.js cluster to utilize multi-core CPUs by forking workers equal to cores, sharing sockets, and maintaining healthy workers with automatic restarts.
a thread is a unit of execution inside a process. multiple threads share memory and each thread has its own program counter, enabling lighter context switching and faster task execution.
Spawn multiple worker threads in a single Node.js process using the worker threads module, organizing code into separate files and logging results back to the main thread.
Map data between the main thread and worker threads by passing data and ensuring it is cloned, not shared by reference. Use a message channel to enable bidirectional communication.
Describe setting up a two-way communication channel between the main thread and a worker with MessageChannel. Send and receive messages via the message port and manage transfer lists.
Learn to coordinate multiple worker threads using message channels and ports, enabling distinct props and post messages between the main thread and workers, with practical setup and debugging tips.
Explain how to use the shorthand MessageChannel syntax in Node.js worker threads, show a two-file setup, create and use a message channel, and send and receive messages between threads.
Share memory inside a Node.js process using SharedArrayBuffer and TypedArray between the main thread and worker threads. Note that this is tricky and that only numbers share directly.
Explore how synchronization and shared memory with two threads can produce race conditions during increments and decrements, and how context switching affects memory writes.
Explore how race conditions arise when multiple threads access the critical section simultaneously, causing unexpected results. Identify the critical vs non-critical sections and preemptive scheduling and context switching.
Demonstrates race condition in practice by using a shared memory buffer and a worker to expose unsynchronized access to a critical section, highlighting the need for proper synchronization.
Learn how atomic operations prevent race conditions in nodejs by executing updates completely or not at all, avoiding context switches during increments and decrements.
Apply synchronization mechanisms to prevent race conditions by guarding critical sections with entry and exit points, ensuring only one thread executes the critical section at a time.
Define mutual exclusion as a synchronization mechanism that ensures only one thread can enter a critical section at a time, despite cpu preemptive scheduling.
Demonstrates the lock synchronization technique to achieve mutual exclusion using a shared boolean lock (0/1) across threads, outlining the critical section and lock release.
Learn to implement a lock in Node.js using a shared lock buffer to protect the critical section, compare atomic versus non-atomic synchronization, and address race conditions.
explain why a lock fails in a Node.js context by showing how atomic operations and compare chain prevent context switching in the critical section.
Explore how deadlock arises when a lock is not released, causing circular waiting and forever blocked threads; ensure release with a proper finally block.
Explore the buffer as a fixed-length container for bytes in Node.js, create it with Buffer.alloc, store data like hello, and convert to hexadecimal with toString('hex').
Learn how buffers wait for all data before writing to disk. See how streams write to the hard disk as data arrives via the fs module.
Demonstrate using node streams to read a video, compress it with zlib, and write chunks into a zip file, illustrating buffers, memory usage, and streaming concepts.
Explore node.js streams, including readable, duplex, and transform types, and write data to a file with a stream, comparing cpu and memory usage to a normal script.
The normal version writes directly to disk, causing high cpu usage and long times. A 16 kB buffered stream reduces writes and cpu load, though memory remains high.
Fix memory issues in the extreme version by handling write returns false in a file stream: pause the loop and resume when the drain event fires.
Explain how a readable stream reads data in chunks, splitting into 16 kilobyte pieces with a 64 kilobyte default buffer, and streams those chunks to a web server.
Read and write data using streams to copy video efficiently, handling backpressure by pausing and resuming the stream and processing data in 16 kB chunks.
Learn to build a custom readable stream in Node.js by extending the stream class, implementing a constructor and the underscore read method, and using internal streams for data events.
Handle backpressure in rich streams by pausing and resuming the internal buffer, and reuse the node syntax provided by Swift to simplify restream logic and avoid duplicating code.
Stream video from server to client by creating a video stream, sending chunks to the response, and finalizing with a header containing title and content.
Compare http and websocket protocols in a chat app context, highlighting http's request–response and one-way data flow versus websocket's bi-directional communication.
Build a simple chat app using http with an Express API to send and fetch messages, updating a browser UI. Then introduce web sockets for bidirectional communication.
Explain the DCB three-way handshake to establish a connection before sending the Artemis request. Describe statelessness and the persistence connection after requests.
Perform an active handshake to upgrade an HTTP request to the WebSocket protocol, enabling the 101 switching protocols response and establishing the WebSocket connection.
Discover how the WebSocket protocol enables bidirectional, real-time communication for chat, stock updates, online games, and video streaming, with examples from popular apps.
NodeJS Deep Dive: Mastering Internals & System Interactions
Have you been working with NodeJS for a while but don't really understand it?
Discover how Node.js truly works under the hood by exploring its internal mechanisms and its interaction with the operating system. This course goes beyond basic usage, providing knowledge of process management, memory handling, and concurrency. You’ll learn how Node.js efficiently handles I/O operations, manages threads, and utilizes system resources to deliver high-performance applications. By understanding these core concepts, you’ll be able to write more optimized, scalable, and reliable Node.js applications.
What You’ll Learn:
Operating System Fundamentals:
The role of RAM, Hard Drive, and CPU in program execution
Programs vs. Processes and different process states
Multi-programming and efficient resource utilization
Preemptive vs. Non-preemptive Scheduling explained
The Program Counter and its significance
How Context Switching works behind the scenes
Node.js Internals:
Understanding V8 and how it executes JavaScript
The role of Libuv in handling asynchronous operations
Compilation vs. Interpretation and JIT (Just-in-Time) Compilation
Concurrency & Performance Optimization:
I/O Tasks vs. CPU Tasks and how Node.js handles Non-blocking I/O
Using Child Processes to offload work
Scaling with Clusters
Worker Threads for parallel execution
Understanding and mitigating Race Conditions