結論先講
同一個底層(Express.js + PM2 × 4),TypeScript 比 JavaScript 快、Sequelize 比 TypeORM 快、NestJS 的 DI 有可見但不致命的開銷。 Express-TS 在 50 VU 時 58 RPS 排 Node.js 生態第一,NestJS 39 RPS 第二,Express-JS 23 RPS 最後——JS 版不是更快,是更慢。
三者的配置
| 項目 | Express-TS | Express-JS | NestJS |
|---|---|---|---|
| 語言 | TypeScript | JavaScript | TypeScript |
| 框架 | Express.js 4 | Express.js 4 | NestJS (Express adapter) |
| ORM | Sequelize | Sequelize | TypeORM |
| Process | PM2 cluster × 4 | PM2 cluster × 4 | PM2 cluster × 4 |
| DB Pool | 20 | 20 | 20 |
| Hash | bcrypt (native) | bcrypt (native) | bcrypt (native) |
三者都用 native bcrypt,不是 bcryptjs。PM2 cluster mode 開 4 個 instance,等於 4 個 Node.js process。
Per-VU 數據對照
10 VU
| 框架 | Avg | P95 | RPS |
|---|---|---|---|
| Express-TS | 71ms | 300ms | 24 |
| NestJS | 86ms | 434ms | 23 |
| Express-JS | 120ms | 223ms | 15 |
Express-TS 最快。NestJS 比 Express-TS 慢 15ms(DI + middleware overhead)。Express-JS 最慢——等等,JavaScript 不是應該比 TypeScript 快嗎?
50 VU
| 框架 | Avg | P95 | RPS |
|---|---|---|---|
| Express-TS | 486ms | 1,593ms | 58 |
| NestJS | 871ms | 2,507ms | 39 |
| Express-JS | 1,510ms | 2,598ms | 23 |
差距更大了。Express-TS 58 RPS,Express-JS 只有 23 RPS——2.5 倍差距。
100 VU
| 框架 | Avg | P95 | RPS |
|---|---|---|---|
| Express-TS | 1,470ms | 3,858ms | 52 |
| NestJS | 1,623ms | 5,182ms | 47 |
| Express-JS | 3,444ms | 10,294ms | 23 |
Express-JS 的 P95 飆到 10 秒。Express-TS 和 NestJS 之間的差距在縮小(bcrypt 開始主導)。
為什麼 TypeScript 比 JavaScript 快
這違反直覺。TypeScript 需要編譯成 JavaScript 才能跑,多一步應該更慢才對?
關鍵在 V8 的 JIT 優化。
TypeScript 的 strict mode 給 V8 更多型別資訊。V8 在 JIT compile 時可以做更激進的優化——例如 inline caching、hidden class optimization。
// TypeScript — V8 知道 user 的結構,可以優化
interface User { id: number; email: string; }
const user: User = await User.findByPk(id);
// JavaScript — V8 要在 runtime 才能推斷型別
const user = await User.findByPk(id);在長時間運行(壓測跑好幾分鐘),V8 有足夠的時間做 JIT 優化。TypeScript 的型別資訊讓 JIT 更早、更準確地做優化。
另外,TypeScript 的編譯過程會做一些靜態分析和 tree shaking,產出的 JavaScript 可能比手寫的 JavaScript 更「V8 friendly」。
但差距不應該 2.5 倍
15 RPS vs 58 RPS 的差距不可能只是 V8 JIT 造成的。更可能的原因是 Express-JS 版本的程式碼品質——可能有 N+1 查詢、多餘的 middleware、或次優的 Sequelize 配置。
這是跨框架比較的一個limitation:我們盡量讓 9 個框架的程式碼邏輯一致,但不同語言/框架的「最佳實踐」不同。Express-JS 版可能沒有被優化到和 Express-TS 版同一水平。
NestJS 的 DI overhead
NestJS 比 Express-TS 慢多少?
| VU | Express-TS | NestJS | 差距 |
|---|---|---|---|
| 10 | 71ms | 86ms | +15ms (+21%) |
| 50 | 486ms | 871ms | +385ms (+79%) |
| 100 | 1,470ms | 1,623ms | +153ms (+10%) |
低 VU 時差距小(15ms),高 VU 時 bcrypt 蓋住差異(+10%)。50 VU 時差距最大(+79%),因為這是「框架 overhead 還可見但 bcrypt 還沒完全主導」的過渡區。
DI overhead 來自哪裡
- Dependency Injection container: NestJS 在每次請求時要 resolve dependencies。Express-TS 直接 import
- Decorator metadata: NestJS 用 TypeScript decorator,runtime 有
Reflect.getMetadata()成本 - Middleware pipeline: NestJS 的 Guards → Interceptors → Pipes → Controller → Interceptors 比 Express 的 middleware chain 長
- TypeORM vs Sequelize: TypeORM 的 query builder 比 Sequelize 多一層抽象
結論:DI overhead 有但不致命
在真實應用中,NestJS 的結構化(DI、Module、Guard、Pipe)帶來的開發效率提升遠超 15ms 的延遲代價。壓測數據說的是「NestJS 比 Express 慢 15ms」,不是「不要用 NestJS」。
PM2 Cluster:4 個 instance 夠嗎
三個框架都用 PM2 cluster × 4。但 Docker 只給 2 核 CPU——4 個 instance 搶 2 核,有沒有浪費?
對 I/O-bound 操作:4 instance > 2 instance。 因為 Node.js 是 single-thread,一個 instance 在等 DB 時 CPU 閒著,另一個 instance 可以用這段時間。
對 CPU-bound 操作(bcrypt):4 instance ≈ 2 instance。 因為 bcrypt 佔 CPU,4 個 instance 搶 2 核不會比 2 個 instance 快多少。
實際數字:Express-TS 在 50 VU 時 58 RPS。如果只開 2 instance,大約 35-40 RPS。4 instance 確實有幫助,但不是線性提升。
Node.js 生態的壓測建議
- 用 native
bcrypt(不是bcryptjs): 效能差 30%,而且不阻塞 event loop - TypeScript 優先: V8 JIT 優化 + 更好的程式碼品質
- PM2 cluster instance 數 = CPU 核數 × 2: 在我們的環境下就是 4
- NestJS 的 overhead 可接受: 除非你的 SLA 要求 P95 < 100ms,否則 NestJS 的結構化值得那 15ms
- ORM 選擇: Sequelize 在原始效能上比 TypeORM 快,但 TypeORM 的 TypeScript 整合更好。看團隊偏好
下一篇
Python 雙雄 CRUD:Django vs FastAPI — Django 排最後,FastAPI 排中間。但 FastAPI 在 10 VU 時是全場最快的(64ms)。GIL 是怎麼影響壓測結果的?uvicorn 和 gunicorn 有什麼差別?
本系列文章
完整 68 篇目錄見 系列首頁
← 上一篇:Go CRUD 壓測:低延遲王者的天花板在哪裡 → 下一篇:Python 雙雄 CRUD:Django vs FastAPI 的 GIL 困境