YouTip LogoYouTip

Nodejs Intro

Node.js Basic Concepts

Node.js is a JavaScript runtime environment built on the Chrome V8 JavaScript engine. Simply put, Node.js allows JavaScript to run on the server side, not just limited to browsers.

Core Features of Node.js

1. Single-Threaded Event Loop
  • Node.js uses a single-threaded event loop model
  • Handles concurrent requests through event-driven programming and callbacks
  • Avoids thread switching overhead found in traditional multi-threaded programming
2. Non-Blocking I/O
  • All I/O operations (file read/write, network requests, etc.) are asynchronous
  • The program is not blocked while waiting for I/O operations to complete, allowing it to continue processing other tasks
  • Significantly improves application throughput
3. Cross-Platform
  • Supports multiple operating systems such as Windows, macOS, and Linux
  • Write once, run anywhere
4. Rich Ecosystem
  • npm (Node Package Manager) has millions of open-source packages
  • An active developer community

Differences from Traditional Server-Side Technologies

1. Traditional Server-Side Technologies (e.g., Apache + PHP): Request 1 β†’ Create Thread 1 β†’ Process Request β†’ Return Response β†’ Destroy Thread 1
Request 2 β†’ Create Thread 2 β†’ Process Request β†’ Return Response β†’ Destroy Thread 2
Request 3 β†’ Create Thread 3 β†’ Process Request β†’ Return Response β†’ Destroy Thread 3 Image 1 2. Node.js Processing Method: Request 1 β†’ Event Loop β†’ Process Request β†’ Return Response
Request 2 β†’ Event Loop β†’ Process Request β†’ Return Response (Reuses the same thread)
Request 3 β†’ Event Loop β†’ Process Request β†’ Return Response Image 2
Feature Traditional Multi-Thread Model Node.js Single-Thread Model
Memory Usage ~2MB per thread Single thread, low memory usage
Concurrency Handling Limited by thread count Event loop handles high concurrency
Context Switching Frequent thread switching overhead No thread switching overhead
Programming Complexity Requires handling thread synchronization Avoids locks and thread synchronization issues
Suitable Scenarios CPU-intensive tasks I/O-intensive tasks

Application Scenarios for Node.js

1. Suitable Application Scenarios

Web Applications
  • RESTful API services
  • Backend services for Single Page Applications (SPAs)
  • Real-time web applications
Real-Time Applications
  • Chat applications
  • Online games
  • Collaboration tools (e.g., online document editing)
Microservices Architecture
  • Lightweight microservices
  • API gateways
  • Inter-service communication
Tools and CLI Applications
  • Build tools (e.g., Webpack, Gulp)
  • Scaffolding tools
  • Automation scripts
Internet of Things (IoT) Applications
  • Device data collection
  • Sensor data processing

2. Unsuitable Application Scenarios

CPU-Intensive Tasks
  • Image/video processing
  • Complex mathematical calculations
  • Big data analytics
Applications Requiring Heavy Computation
  • Machine learning training
  • Scientific computing
  • Cryptocurrency mining

Event-Driven and Non-Blocking I/O Models

Example of Traditional Blocking I/O Model:

Example

// Pseudo code - Blocking operation

// Each readFileSync will "freeze" the program, waiting for the file read to finish before continuing

const data1 = readFileSync('file1.txt');// Program pauses here, waiting for read to complete

const data2 = readFileSync('file2.txt');// After data1 is read, pauses again to wait

const data3 = readFileSync('file3.txt');// After data2 is read, pauses again to wait

console.log('All files read complete');// Only executes here after all three files are fully read

// Total time = Time to read file1 + Time to read file2 + Time to read file3
Example of Node.js Non-Blocking I/O Model:

Example

// Node.js asynchronous operation

const fs = require('fs');

// The three file reading operations are issued almost simultaneously, the program does not wait for any of them to complete

fs.readFile('file1.txt',(err, data1)=>{

// This callback function will be automatically called after file1.txt is read

console.log('File 1 read complete');

});

fs.readFile('file2.txt',(err, data2)=>{

// This callback function will be automatically called after file2.txt is read

console.log('File 2 read complete');

});

fs.readFile('file3.txt',(err, data3)=>{

// This callback function will be automatically called after file3.txt is read

console.log('File 3 read complete');

});

// Note: This line of code will execute FIRST! Because the three file reading operations above are asynchronous,

// the program immediately continues downward after issuing the read requests, without waiting for file reads to complete

console.log('Program continues execution, does not wait for file reads');

// Actual output order example:

// Program continues execution, does not wait for file reads  ← Printed first

// File 2 read complete ← Whichever file finishes reading first gets printed, order is not fixed

// File 1 read complete

// File 3 read complete

// Total time β‰ˆ Time taken by the slowest of the three files (concurrent execution, rather than sequential addition)
Event Loop Mechanism: The event loop is the core mechanism that enables non-blocking I/O in Node.js. It runs continuously, constantly checking for pending tasks, thereby achieving the effect of "handling concurrency with a single thread": 1. **Call Stack**: Executes synchronous code; functions are pushed onto the stack when called and popped off after execution. 2. **Event Queue**: Stores callback functions after asynchronous operations complete, waiting to be executed sequentially when the call stack is free. 3. **Event Loop**: Continuously monitors the call stack and event queue. Once the call stack is empty, it pops callbacks from the event queue and pushes them onto the call stack for execution. The event loop processes the following phases in a fixed order:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”Œβ”€>β”‚ timers β”‚ ← Execute expired callbacks for setTimeout, setIntervalβ”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚ pending callbacks β”‚ ← Execute delayed I/O callbacks from the previous loop cycle (e.g., certain system error callbacks)β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚ idle, prepare β”‚ ← Used internally by Node.js, developers generally do not need to worry about thisβ”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚ poll β”‚ ← Core phase: fetch new I/O events and execute their callbacks (e.g., file reads, network request completions)β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚ check β”‚ ← Execute setImmediate callbacks (executed immediately after the poll phase)β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β””β”€β”€β”€ close callbacks β”‚ ← Execute closing event callbacks, e.g., socket.on('close', ...) β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
For beginners, the most important thing to remember is: **Synchronous code always executes first, while asynchronous callbacks (such as handling completed file reads) will only execute after the call stack is cleared.**

JavaScript Runtime Environment

Introduction to the V8 Engine

V8 is a high-performance JavaScript engine developed by Google and serves as the core component of the Chrome browser. Node.js uses the V8 engine to execute JavaScript code. V8 Engine Features: Just-In-Time (JIT) Compilation
  • Compiles JavaScript code directly into machine code
  • No intermediate bytecode required, resulting in higher execution efficiency
Garbage Collection
  • Automatic memory management; developers do not need to manually free memory
  • Uses a generational garbage collection algorithm, dividing memory into young and old generations for separate management to improve recycling efficiency
Optimization Techniques
  • Inline Caching: Caches object property lookup results to avoid repeated lookups
  • Hidden Classes: Staticizes object structures in dynamic languages to accelerate property access
  • Dynamic Optimization: Analyzes hot code at runtime and applies targeted optimizations

Browser JavaScript vs. Node.js JavaScript

Although both use the JavaScript language, differences in their runtime environments lead to several important distinctions: Similarities:
  • Both use the same JavaScript syntax
  • Both support ES6+ features
  • Both use the V8 engine (in Chrome browser)
Differences:
Feature Browser JavaScript Node.js JavaScript
Global Object window global
Module System ES6 modules, AMD CommonJS, ES6 modules
File System Access Inaccessible (due to security restrictions) Fully accessible
Network Requests XMLHttpRequest, Fetch http, https modules
DOM Manipulation Supported (manipulates page elements) Not supported (no pages on the server side)
Process Control Not supported Supported (can read environment variables, exit processes, etc.)
Browser Environment Example:

Example

// Global object and DOM manipulation in the browser

console.log(window);// Browser global object, contains all browser APIs

document.getElementById('app');// Get page element by ID (unavailable in Node.js)

localStorage.setItem('key','value');// Browser local storage (unavailable in Node.js)
Node.js Environment Example:

Example

// Global object and file operations in Node.js

console.log(global);// Node.js global object (corresponds to window in the browser)

const fs = require('fs');// Import built-in file system module (unavailable in browser)

fs.readFile('data.txt','utf8', callback);// Read server local file (unavailable in browser)

Differences in Global Objects

Global Object in Browser:

Example

// Browser environment

console.log(this === window);// true, top-level this is the window object

var globalVar ='hello';

console.log(window.globalVar);// 'hello', variables declared with var become properties of window
Global Object in Node.js:

Example

// Node.js environment

// Note: In Node.js, each file is an independent module, and this inside a module does not equal global

console.log(this === global);// false (in module scope, this points to module.exports)

var globalVar ='hello';

console.log(global.globalVar);// undefined, variables inside a module are not automatically attached to global

// Module scope in Node.js

console.log(this);// {} Empty object, i.e., the initial value of module.exports

console.log(module.exports === this);// true, inside a module this points to module.exports
Node.js-Specific Global Variables:

Example

console.log(__dirname);// Absolute path of the directory where the current module resides, e.g., /home/user/project

console.log(__filename);// Absolute path of the current module file, e.g., /home/user/project/app.js

console.log(process);// Process object, can read command-line arguments (process.argv), environment variables (process.env), etc.

console.log(Buffer);// Constructor for handling binary data, commonly used for file read/write and network communication

Advantages and Limitations of Node.js

Detailed Advantages

1. High Concurrency Handling Capability A traditional multi-threaded server requires approximately 20GB of memory to handle 10,000 concurrent connections (~2MB per thread), whereas Node.js can handle the same number of connections with significantly less memory.

Example

// Node.js high concurrency example

const http = require('http');

const server = http.createServer((req, res)=>{

// Simulate asynchronous operation (e.g., database query), return response after 100ms

// During these 100ms, the event loop can continue processing other requests without being blocked

setTimeout(()=>{

res.writeHead(200,{'Content-Type':'text/plain'});

res.end('Hello Worldn');

},100);

});

server.listen(3000,()=>{

console.log('Server running at http://localhost:3000/');

});

// Thanks to non-blocking I/O and the event loop mechanism, this server can handle thousands of requests simultaneously without blocking
2. Rapid Development A unified JavaScript language stack (using JavaScript for both frontend and backend) makes full-stack development more efficient. Developers only need to master one language to write both frontend and backend code, and can share logic across both ends:

Example

// The same validation logic can be reused on both frontend and backend without rewriting

function validateEmail(email){

const regex =/^[^s@]+@[^s@]+.[^s@]+$/;

return regex.test(email);

}

// Frontend usage (runs in browser): Validates user input before form submission to prevent invalid requests from reaching the server

if(validateEmail(userInput)){

// Validation passed, send to server

}

// Backend usage (runs in Node.js): Server validates again to prevent bypassing the frontend and directly calling the API

if(validateEmail(req.body.email)){

// Validation passed, save to database

}
3. Advantages of a Unified Language Stack
  • Code Reusability: Frontend and backend can share utility functions, data validation logic, constant definitions, etc.
  • Team Efficiency: Developers can work on both frontend and backend simultaneously, reducing communication costs
  • Simplified Tech Stack: Only requires mastering JavaScript, lowering learning costs and technical complexity
4. Rich npm Ecosystem
# npm provides millions of open-source packages; you can almost always find a ready-made library for any functionality
npm search express # Search for a package named 'express'
npm install express # Install the 'express' package into the current project
npm update # Update all packages in the current project to the latest compatible versions

Limitation Analysis

1. Performance Issues with CPU-Intensive Tasks

Example

// Bad example: CPU-intensive tasks will block the event loop
// fibonacciSync is a pure computation task that will continuously occupy the CPU, preventing the event loop from handling other requests during this time

function fibonacciSync(n){

if(n <2)return n;

return fibonacciSync(n -1)+ fibonacciSync(n -2);

}

// This will block the entire application for several seconds, during which no requests can be responded to

console.log(fibonacciSync(40));

// Solution: Use Worker Threads to offload CPU-intensive tasks to independent threads,

// so the main thread's event loop won't be blocked

const{ Worker, isMainThread, parentPort, workerData }= require('worker_threads');

if(isMainThread){

// Main thread: Creates a Worker and passes the parameter { n: 40 } to it

// The Worker will execute this file in an independent thread (__filename refers to the current file path)

const worker =new Worker(__filename,{

workerData:{ n:40}

});

// Listen for messages from the Worker (calculation results)

worker.on('message',(result)=>{

console.log('Result:', result);// After the Worker finishes calculating, the main thread receives the result here

});

}else{

// Worker thread: Retrieves parameters passed from the main thread via workerData, performs the calculation, and sends back the result

const result = fibonacciSync(workerD
← Nodejs AsynchronousMd Quiz β†’