Node.js Runtime Basics
Node.js executes JavaScript outside the browser, meaning browser-specific APIs like window or document are unavailable. Verify the installation using node -v and execute scripts via node app.js.
console.log('Executing within Node runtime');
console.log(window); // Throws ReferenceError
console.log(document); // Throws ReferenceErrorBinary Data Handling with Buffer
Buffer instances represent fixed-size chunks of raw binary data allocated in memory. They operate similarly to arrays of integers but correspond directly to raw memory allocations, where each element consumes exactly one byte.
Buffer Instantiation
Creation methods include allocating zero-filled memory, allocating uninitialized memory, and converting existing data structures.
// Allocates 8 bytes initialized to zero
const safeBuffer = Buffer.alloc(8); // <Buffer 00 00 00 00 00 00 00 00>
// Allocates 8 bytes without initialization (potentially contains old data)
const fastBuffer = Buffer.allocUnsafe(8);
// Creates buffer from a string
const textBuffer = Buffer.from('nodejs');
// Creates buffer from an array of byte values
const arrayBuffer = Buffer.from([110, 111, 100, 101]);Data Conversion and Access
Use toString() (defaults to UTF-8) to decode buffers. Individual bytes can be accessed or modified using index notation. Overflows beyond 255 are truncated to the lower 8 bits. A single UTF-8 Chinese character typically occupies 3 bytes.
console.log(arrayBuffer.toString()); // "node"
console.log(textBuffer[0]); // 110 (ASCII for 'n')
textBuffer[0] = 109; // Modifies first byte
console.log(textBuffer.toString()); // "modejs"File System Operations
The fs module enables interaction with the operating system's file system. Operations are categorized into synchronous, asynchronous callback, and streaming methodologies.
Writing Data
| Method | Description |
|---|---|
writeFile | Asynchronous file write |
writeFileSync | Synchronous file write |
appendFile | Asynchronous append to file |
createWriteStream | Streaming data write |
const fileSystem = require('fs');
// Asynchronous write
fileSystem.writeFile('./docs/note.txt', 'Initial content', (writeErr) => {
if (writeErr) throw writeErr;
console.log('Write operation completed');
});
// Synchronous write
fileSystem.writeFileSync('./logs/sys.txt', 'Log entry');
// Appending data
fileSystem.appendFileSync('./docs/note.txt', '\nAppended text');
// Streaming write (ideal for large or continuous data)
const streamWriter = fileSystem.createWriteStream('./media/video.mp4');
streamWriter.write('Chunk 1');
streamWriter.write('Chunk 2');
streamWriter.end();Synchronous methods block the main thread until the I/O completes, whereas asynchronous methods delegate operations to background threads, executing a callback upon completion. Streaming minimizes file open/close overhead, optimizing frequent write scenarios.
Reading Data
const fileSystem = require('fs');
// Asynchronous read (returns Buffer unless encoding specified)
fileSystem.readFile('./docs/note.txt', 'utf8', (readErr, fileData) => {
if (readErr) throw readErr;
console.log(fileData);
});
// Synchronous read
const rawContent = fileSystem.readFileSync('./docs/note.txt');
console.log(rawContent.toString('utf8'));
// Streaming read (processes data in chunks)
const streamReader = fileSystem.createReadStream('./media/video.mp4', 'utf8');
streamReader.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes`);
});
streamReader.on('end', () => {
console.log('Stream finished');
});File Management
Renaming, moving, and deleting files utilize rename/unlink and their synchronous counterparts.
fileSystem.rename('./docs/note.txt', './archive/old_note.txt', (err) => {
if (err) throw err;
});
fileSystem.unlink('./archive/old_note.txt', (err) => {
if (err) throw err;
});Directory Management
// Creating directories (recursive option builds nested paths)
fileSystem.mkdir('./storage/data', { recursive: true }, (err) => {
if (err) throw err;
});
// Reading directory contents
fileSystem.readdir('./storage', (err, files) => {
if (err) throw err;
console.log(files);
});
// Removing directories (recursive removes nested content)
fileSystem.rmdir('./storage', { recursive: true }, (err) => {
if (err) throw err;
});Path Resolution and Metadata
Relative paths reference the command line's working directory, not the script's location. The global __dirname variable provides the absolute path of the current script directory, ensuring reliable file references.
const stats = fileSystem.statSync('./docs/note.txt');
console.log(stats.isFile()); // true
console.log(stats.isDirectory()); // falsePath Manipulations
The path module standardizes path operations across different operating systems.
const pathModule = require('path');
const fullPath = 'C:\projects\web\src\app.js';
console.log(pathModule.sep); // '\' on Windows, '/' on POSIX
console.log(pathModule.resolve(__dirname, 'config.json')); // Absolute path
console.log(pathModule.parse(fullPath)); // { root, dir, base, ext, name }
console.log(pathModule.basename(fullPath)); // 'app.js'
console.log(pathModule.dirname(fullPath)); // 'C:\projects\web\src'
console.log(pathModule.extname(fullPath)); // '.js'Building HTTP Servers
The http module allows creation of raw web servers. The server processes incoming requests and constructs responses.
const httpModule = require('http');
const webServer = httpModule.createServer((clientReq, serverRes) => {
serverRes.setHeader('Content-Type', 'text/html; charset=utf-8');
serverRes.end('<h1>Server Active</h1>');
});
webServer.listen(8080, () => {
console.log('Server running on port 8080');
});The clientReq object contains request details (method, URL, headers). request.url only yields the path and query string. The serverRes object sends data back to the client, and response.end() must be called to finalize every request.
Serving Static Assets
Static assets (images, stylesheets) remain unchanged over time. The server can read files based on the request URL and stream them back. Setting the correct Content-Type (MIME type) is essential; unknown types default to application/octet-stream, prompting a file download.
const fileSystem = require('fs');
const httpModule = require('http');
const staticServer = httpModule.createServer((req, res) => {
const targetPath = pathModule.join(__dirname, 'public', req.url);
fileSystem.readFile(targetPath, (err, data) => {
if (err) {
res.statusCode = 404;
res.end('Resource not found');
return;
}
res.end(data);
});
});
staticServer.listen(8080);Module Systems
Modularization divides complex applications into isolated files, preventing naming conflicts and enhancing reusability.
CommonJS
Node.js natively implements CommonJS, utilizing require() for importing and module.exports or exports for exporting. Exports ultimately reference module.exports; reassigning exports directly breaks the binding.
// utils.js
function calculateSum(a, b) { return a + b; }
module.exports = { calculateSum };
// main.js
const utilities = require('./utils');
console.log(utilities.calculateSum(2, 5));Custom modules require relative paths (prefixed with ./ or ../). Module resolution checks node_modules, package.json main field, and index.js fallbacks.
ES Modules
ES Modules employ static import/export syntax, enabling tree-shaking optimizations. Node.js requires "type": "module" in package.json or .mjs extensions. Browser environments use <script type="module">.
// math.mjs
export default function multiply(x, y) { return x * y; }
export function subtract(x, y) { return x - y; }
// app.mjs
import multiply, { subtract } from './math.mjs';
console.log(multiply(4, 3));
console.log(subtract(10, 6));Package Management
Node Package Manager (npm) handles dependency lifecycle. Initializing a project generates a package.json manifest.
npm init -y
npm install express --save
npm install eslint --save-dev
npm uninstall eslintDependencies essential for runtime belong in dependencies, while build-time tools reside in devDependencies. Global installations (-g) register CLI tools like nodemon.
Mirror Configuration
Using the nrm registry manager accelerates downloads.
npm install -g nrm
nrm use taobaoYarn
Yarn offers deterministic installations via lockfiles and parallel downloading.
yarn init
yarn add express
yarn add eslint --dev
yarn remove eslintManaging Node Versions
Node Version Manager (nvm) allows switching between multiple Node.js runtime versions.
nvm install 18.0.0
nvm use 18.0.0
nvm listExpress Framework
Express abstracts the raw http module, providing robust routing, middleware support, and simplified response handling.
const expressApp = require('express');
const app = expressApp();
app.get('/api/status', (req, res) => {
res.send({ status: 'Operational' });
});
app.listen(3000);Routing and Parameters
Routes map HTTP methods and paths to handler functions. Query strings populate req.query, while dynamic URL segments map to req.params.
app.get('/users/:userId', (req, res) => {
res.send(`Fetching user ${req.params.userId}`);
});Middleware Architecture
Middleware functions intercept requests, executing logic before passing control via next(). Global middleware binds via app.use(), while route-specific middleware applies to individual endpoints.
const authCheck = (req, res, next) => {
if (!req.headers.authorization) return res.status(401).send('Unauthorized');
next();
};
app.use(expressApp.static('assets')); // Static middleware
app.use(expressApp.urlencoded({ extended: false })); // Body parsing middleware
app.get('/admin', authCheck, (req, res) => res.send('Admin Panel'));Router Modularity
The express.Router() class creates modular, mountable route handlers.
// userRoutes.js
const router = expressApp.Router();
router.get('/', (req, res) => res.send('User List'));
module.exports = router;
// app.js
const userRoutes = require('./userRoutes');
app.use('/users', userRoutes);EJS Templating
Embedding JavaScript into HTML via EJS (<%= variable %>) enables dynamic server-side rendering.
app.set('view engine', 'ejs');
app.get('/dashboard', (req, res) => {
res.render('dashboard', { user: 'Admin' });
});MongoDB and Mongoose
MongoDB stores data as BSON documents within collections. The Mongoose ODM bridges Node.js and MongoDB, enforcing schema validation.
Database Connection
const mongooseODM = require('mongoose');
mongooseODM.connect('mongodb://localhost:27017/appdb');
const itemSchema = new mongooseODM.Schema({
title: { type: String, required: true, unique: true },
category: { type: String, enum: ['tech', 'sports', 'art'] },
price: { type: Number, default: 0 }
});
const ItemModel = mongooseODM.model('Item', itemSchema);CRUD Operations
// Create
ItemModel.create({ title: 'Laptop', category: 'tech', price: 999 });
// Read
ItemModel.find({ category: 'tech' });
ItemModel.findById('abc123');
// Update
ItemModel.updateOne({ title: 'Laptop' }, { price: 899 });
ItemModel.findByIdAndUpdate('abc123', { price: 799 });
// Delete
ItemModel.deleteOne({ title: 'Laptop' });Query Conditions
Comparison operators ($gt, $lt, $gte, $lte, $ne) and logical operators ($or, $and) filter data. Regular expressions enable fuzzy searches.
ItemModel.find({ price: { $gte: 100, $lte: 500 } });
ItemModel.find({ $or: [{ category: 'tech' }, { category: 'art' }] });
ItemModel.find({ title: /^Lap/ });Projections exclude/include fields, sorting orders results, and skip/limit implements pagination.
ItemModel.find().select({ title: 1, _id: 0 }).sort({ price: -1 }).skip(10).limit(5);API Design
RESTful APIs map HTTP verbs (GET, POST, PUT, DELETE) to CRUD operations on resource-based URLs, avoiding verbs in endpoints. json-server rapidly prototypes REST backends from JSON files.
npm install -g json-server
json-server --watch mock_db.jsonState Management
HTTP lacks inherent state. Mechanisms like Cookies, Sessions, and Tokens persist user context.
Cookies
Cookies store small data strings client-side, transmitted automatically with matching domain requests.
res.cookie('sessionId', 'xyz789', { maxAge: 3600000, httpOnly: true });
res.clearCookie('sessionId');Sessions
Sessions reside server-side, mapping a client cookie (containing an ID) to stored data.
const sessionMiddleware = require('express-session');
app.use(sessionMiddleware({
secret: 'encryption_key',
resave: false,
saveUninitialized: true,
cookie: { secure: false }
}));
req.session.userRole = 'admin';Tokens (JWT)
JSON Web Tokens encode user claims within a cryptographically signed string, residing entirely client-side, ideal for mobile applications and cross-service authentication.
const jwtLib = require('jsonwebtoken');
const generatedToken = jwtLib.sign({ userId: 123 }, 'secret_key', { expiresIn: '1h' });
jwtLib.verify(generatedToken, 'secret_key');Console Inspection
To output deeply nested object structures completely, specify infinite depth.
console.dir(complexObject, { depth: null, colors: true });