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
- 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
- Supports multiple operating systems such as Windows, macOS, and Linux
- Write once, run anywhere
- 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 1Request 2 β Create Thread 2 β Process Request β Return Response β Destroy Thread 2
Request 3 β Create Thread 3 β Process Request β Return Response β Destroy Thread 3
Request 2 β Event Loop β Process Request β Return Response (Reuses the same thread)
Request 3 β Event Loop β Process Request β Return Response
| 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
- Chat applications
- Online games
- Collaboration tools (e.g., online document editing)
- Lightweight microservices
- API gateways
- Inter-service communication
- Build tools (e.g., Webpack, Gulp)
- Scaffolding tools
- Automation scripts
- Device data collection
- Sensor data processing
2. Unsuitable Application Scenarios
CPU-Intensive Tasks- Image/video processing
- Complex mathematical calculations
- Big data analytics
- 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
- 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
- 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)
| 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.) |
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
# 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 TasksExample
// 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
YouTip