Node.js 零 基礎入門與核心語法
適用對象:完全沒接觸過 Node.js 的同學
目標:從 0 到能寫 CLI、小型 HTTP 服務、文件腳本、調用系統/網絡資源
目錄
- 什么是 Node.js
- 安裝與運行
- 運行腳本與 REPL
- 模塊體系:CommonJS 與 ES Modules
- 基礎語法在 Node 環境下的差異與全局對象
- 內置核心模塊概覽與常用模塊
- 異步編程:回調 → Promise → async/await
- 事件循環與微任務/宏任務(Node 特性)
- Buffer 與二進制
- Stream(流)與管道、背壓
- HTTP:原生 http 模塊
- 使用 Express 快速開發
- 環境變量與配置
- 調試、熱重載、腳手架
- 實戰:小項目骨架(原生與 Express)
- 常見錯誤與最佳實踐
1. 什么是 Node.js
- Node.js 是一個基于 V8 引擎的 JavaScript 運行時,提供了對文件、網絡、進程等系統能力的訪問。
- 單線程、事件驅動、非阻塞 I/O,擅長 I/O 密集任務(HTTP 網關、代理、BFF、CLI、任務腳本等)。
2. 安裝與運行
- 建議安裝 LTS 版本:
https://nodejs.org/
- 包管理器:npm 隨 Node 附帶,也可以用
yarn
/pnpm
- 常用命令:
node -v
npm -v
npm config set registry https://registry.npmmirror.com # 切國內鏡像(可選)
3. 運行腳本與 REPL
- 運行文件:
node app.js
- 交互式 REPL:
node
回車后直接執行表達式
// app.js
console.log('Hello Node');
4. 模塊體系:CommonJS 與 ES Modules
Node 支持兩種模塊系統。
A) CommonJS(CJS)默認
- 文件后綴通常
.js
,require()
引入,module.exports/exports
導出
// lib/math.js (CommonJS)
exports.add = (a,b) => a + b;// app.js
const { add } = require('./lib/math');
console.log(add(2,3));
B) ES Modules(ESM)
- 在 package.json 中設置
"type": "module"
,或使用.mjs
后綴 - 使用
import / export
// package.json
{"name": "demo","type": "module","version": "1.0.0"
}
// lib/math.js (ESM)
export const add = (a,b) => a + b;// app.js
import { add } from './lib/math.js';
console.log(add(2,3));
C) ESM 的 __dirname
、__filename
替代:
// ESM 獲取當前文件路徑
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
5. 基礎語法在 Node 環境下的差異與全局對象
- 瀏覽器的
window
在 Node 中不存在,Node 的全局是global
(等價于globalThis
) - 常見全局:
process
/Buffer
/__dirname
(CJS)/setTimeout
/console
等
console.log(globalThis === global); // true
console.log('cwd', process.cwd()); // 當前工作目錄
6. 內置核心模塊概覽與常用模塊
按頻率與實用性排序(以 ESM 寫法;CJS 用 require 即可):
6.1 path:路徑拼接與解析
import path from 'node:path';console.log(path.join('/a', 'b', 'c.txt')); // \a\b\c.txt (win)
console.log(path.resolve('a/b', '../c')); // 絕對路徑
console.log(path.extname('file.tar.gz')); // .gz
6.2 fs:文件系統(同步/回調/Promise)
// Promise API(推薦):node >= 14
import { readFile, writeFile, mkdir } from 'node:fs/promises';
import path from 'node:path';const p = path.join(process.cwd(), 'data.txt');
await writeFile(p, 'hello\n', { flag: 'a' });
const content = await readFile(p, 'utf-8');
console.log(content);
6.3 os:系統信息
import os from 'node:os';
console.log(os.platform(), os.cpus().length, os.totalmem());
6.4 url:URL 與文件路徑互轉
import { URL, fileURLToPath } from 'node:url';
const u = new URL('https://example.com?a=1');
console.log(u.searchParams.get('a')); // 1
6.5 events:事件總線
import { EventEmitter } from 'node:events';
const bus = new EventEmitter();
bus.on('tick', (n) => console.log('tick', n));
bus.emit('tick', 1);
6.6 child_process:子進程
import { exec } from 'node:child_process';
exec('node -v', (err, stdout) => console.log(stdout));
7. 異步編程:回調 → Promise → async/await
7.1 回調風格(歷史)
import { readFile } from 'node:fs';
readFile('a.txt', 'utf-8', (err, data) => {if (err) return console.error(err);console.log(data);
});
7.2 Promise 風格
import { readFile } from 'node:fs/promises';
readFile('a.txt', 'utf-8').then(console.log).catch(console.error);
7.3 async/await(推薦)
import { readFile } from 'node:fs/promises';async function main() {try {const data = await readFile('a.txt', 'utf-8');console.log(data);} catch (e) {console.error(e);}
}
main();
7.4 并發與控制
// 同時并發 3 個任務,等待全部完成
await Promise.all([fetch(url1), fetch(url2), fetch(url3)
]);// 并發限制:自寫一個簡單限流器
function pLimit(limit){const queue = [];let active = 0;const next = () => {active--;if (queue.length) queue.shift()();};return fn => (...args) => new Promise((res, rej) => {const run = () => {active++;fn(...args).then(res, rej).finally(next);};active < limit ? run() : queue.push(run);});
}
8. 事件循環與微任務/宏任務(Node 特性)
Node 的隊列優先級(簡化理解):
process.nextTick
(比微任務還早)- 微任務(Promise.then/queueMicrotask)
- 宏任務(timers、I/O、setImmediate)
setTimeout(()=>console.log('timeout')); // 宏任務
setImmediate(()=>console.log('immediate')); // 宏任務(檢查階段)
Promise.resolve().then(()=>console.log('micro')); // 微任務
process.nextTick(()=>console.log('nextTick')); // 最早// 輸出:nextTick -> micro -> (timeout/immediate 先后與上下文有關)
9. Buffer 與二進制
- Buffer 是 Node 操作二進制數據的結構
const buf = Buffer.from('abc', 'utf-8');
console.log(buf, buf.toString('hex'));const copy = Buffer.alloc(3);
buf.copy(copy);
console.log(copy.toString()); // 'abc'
10. Stream(流)與管道、背壓
四類流:Readable / Writable / Duplex / Transform
import { createReadStream, createWriteStream } from 'node:fs';
const rs = createReadStream('in.txt');
const ws = createWriteStream('out.txt');
rs.pipe(ws); // 自動處理背壓
自定義 Transform:
import { Transform } from 'node:stream';const upper = new Transform({transform(chunk, enc, cb){cb(null, chunk.toString().toUpperCase());}
});
process.stdin.pipe(upper).pipe(process.stdout);
11. HTTP:原生 http 模塊
11.1 最小 HTTP 服務
import http from 'node:http';const server = http.createServer((req,res)=>{res.writeHead(200, {'Content-Type':'application/json'});res.end(JSON.stringify({ ok:1, path:req.url }));
});server.listen(3000, ()=>console.log('http://localhost:3000'));
11.2 路由與 JSON 解析(最簡)
import http from 'node:http';const server = http.createServer(async (req,res)=>{if (req.method==='POST' && req.url==='/echo'){let body='';for await (const chunk of req) body += chunk;res.setHeader('Content-Type','application/json');return res.end(JSON.stringify({ body: JSON.parse(body) }));}res.statusCode = 404;res.end('Not Found');
});server.listen(3000);
12. 使用 Express 快速開發
npm init -y
npm i express
// app.js (CommonJS 例)
const express = require('express');
const app = express();
app.use(express.json());app.get('/ping', (req,res)=>res.json({pong:1}));
app.post('/echo', (req,res)=>res.json(req.body));app.listen(3000, ()=>console.log('http://localhost:3000'));
ESM 寫法:
// package.json -> "type":"module"
import express from 'express';
const app = express();
app.use(express.json());
app.get('/ping', (req,res)=>res.json({pong:1}));
app.listen(3000);
13. 環境變量與配置
- 使用
process.env
讀取 - 推薦
.env
與dotenv
:
npm i dotenv
import 'dotenv/config';
console.log(process.env.DB_HOST);
.env
:
DB_HOST=localhost
DB_USER=root
14. 調試、熱重載、腳手架
- 調試:VS Code 中直接“Run and Debug” → Node.js
- 熱重載:
npm i -D nodemon
,package.json:
"scripts": {"dev": "nodemon app.js"
}
- 腳手架/工具:ts-node、tsx、vite-node(進階)
15. 實戰:小項目骨架
15.1 原生 http 版項目結構
my-http/
├─ package.json
├─ app.js
└─ lib/└─ router.js
package.json
{"name": "my-http","type": "module","version": "1.0.0","scripts": { "start": "node app.js" }
}
lib/router.js
export async function handle(req, res) {if (req.method === 'GET' && req.url === '/ping') {res.writeHead(200, {'Content-Type':'application/json'});return res.end(JSON.stringify({ pong:1 }));}res.statusCode = 404; res.end('Not Found');
}
app.js
import http from 'node:http';
import { handle } from './lib/router.js';http.createServer(handle).listen(3000, ()=>console.log('http://localhost:3000'));
15.2 Express 版項目結構
my-express/
├─ package.json
└─ app.js
package.json
{"name": "my-express","version": "1.0.0","scripts": { "dev": "nodemon app.js", "start": "node app.js" },"dependencies": { "express": "^4.19.0" },"devDependencies": { "nodemon": "^3.0.0" }
}
app.js
const express = require('express');
const app = express();
app.use(express.json());app.get('/users/:id', (req,res)=>res.json({ id:req.params.id }));
app.post('/users', (req,res)=>res.status(201).json(req.body));app.use((err,req,res,next)=>{console.error(err); res.status(500).json({ message:'server error' });
});app.listen(3000, ()=>console.log('http://localhost:3000'));
16. 常見錯誤與最佳實踐
- 明確模塊體系:CJS vs ESM,不要混用不清。Node 18+ 推薦 ESM
- 文件/網絡 I/O 一律用 Promise/async
- 注意事件循環優先級:
process.nextTick
僅用于兼容/必要場景,慎用 - 使用
fs/promises
與流(大文件) - 錯誤處理:
try/catch
、Express 中用錯誤中間件 - 生產建議:使用 PM2/容器編排;日志落地到文件(winston/pino)
- 安全:避免
eval
,校驗輸入,使用 Helmet(Express)等中間件
附:常用代碼速查
package.json(CJS)
{"name": "demo","version": "1.0.0","main": "app.js","scripts": { "start": "node app.js" }
}
package.json(ESM)
{"name": "demo","version": "1.0.0","type": "module","scripts": { "start": "node app.js" }
}
頂層 await(ESM)
// app.mjs or "type":"module"
import { readFile } from 'node:fs/promises';
const txt = await readFile('a.txt','utf-8');
console.log(txt);
推薦學習順序
- 安裝與運行、REPL → 模塊體系(CJS/ESM)
- fs/path/os/url/events 等常用模塊 → 異步編程(Promise/async)
- 事件循環 → Buffer/Stream → HTTP/Express
- 環境變量/調試 → 小項目實戰 → 最佳實踐與部署