慣性聚合 高效追蹤和閱讀你感興趣的部落格、新聞、科技資訊
閱讀原文 在慣性聚合中打開

推薦訂閱源

博客园 - 司徒正美
V
V2EX
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
月光博客
月光博客
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
Node.js 事件迴圈架構 — 單線程執行時如何處理龐大並發
Raj Dutta · 2026-05-24 · via DEV Community

當我第一次開始使用Node.js時,有一件事讓我覺得不對勁:

一個單線程的系統如何能同時處理成千上萬的請求?

聽起來很矛盾。但一旦我正確理解了事件迴圈(特別是從官方文件中),一切就豁然開朗了。這篇博客是我嘗試以最簡單的方式解釋它,同時不失去深度。


「單執行緒」其實是什麼意思

Node.js 常常被稱為 單執行緒,但這個說法是不完整的.

  • JavaScript 執行在 一個主執行緒
  • 但 Node.js 本身是 不僅限於一次一個操作
  • 它使用:

    • 作業系統核心
    • 背景執行緒 (libuv)
    • 非同步 I/O

→ 所以正確的陳述是:

Node.js 是 單執行緒的,用於 JavaScript 執行,但 多系統的,用於處理 I/O

這個區別至關重要.


核心概念:事件驅動、非阻塞性架構

Node.js不會等待任務完成

相反,它遵循這個模式:

  1. 接收請求
  2. 開始任務(DB呼叫、檔案讀取、API呼叫)
  3. 不等待
  4. 移至下一個請求
  5. 結果準備好時再回來

這被稱為非阻擋 I/O.

→ 從官方文件:
Node.js 在可能時將作業委派給系統,所以主執行緒保持自由.


考慮這樣想(簡單類比)

想像:

  • 你是一位服務生(事件迴圈)
  • 廚房 = 作業系統 / 背景工作員

你:

  • 接收訂單
  • 將其傳遞給廚房
  • 上傳完成的菜餚

你不需要:

  • 親自下廚
  • 空等單一訂單

這正是Node.js的擴展方式.


深入探討:事件迴圈階段

事件迴圈不僅僅是一個佇列。它在階段中運行,各自處理特定類型的回調。

架構:

主要階段:

  1. 計時器
  • 執行來自setTimeout()setInterval()
  1. 的回調
  • 處理系統級回調(例如TCP錯誤)
  1. 閒置 / 準備
  • 內部使用(不是我們處理的內容)
  1. 投票階段(最重要)
  • 取得新的 I/O 事件
  • 執行 I/O 回調
  • 若無事可做則等待
  1. 檢查階段
  • 執行 setImmediate() 回調
  1. 關閉回調
  • 執行清理回調(例如 socket.on('close')
   ┌───────────────────────────┐
   │           timers          │
   └─────────────┬─────────────┘
                 │
                 v
   ┌───────────────────────────┐
┌─>│     pending callbacks     │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │       idle, prepare       │
│  └─────────────┬─────────────┘      ┌───────────────┐
│  ┌─────────────┴─────────────┐      │   incoming:   │
│  │           poll            │<─────┤  connections, │
│  └─────────────┬─────────────┘      │   data, etc.  │
│  ┌─────────────┴─────────────┐      └───────────────┘
│  │           check           │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │      close callbacks      │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
└──┤           timers          │
   └───────────────────────────┘

進入全螢幕模式 退出全螢幕模式

→ 這個迴圈會持續地遍歷這些內容.


為何輪詢階段是核心

這裡就是奇蹟發生的地方.

  • 即將進入的請求會在此處處理
  • 完成的非同步任務會回傳至此
  • 如果沒有排隊的任務 → 訪問點會高效地等待

→ 這就是為什麼 Node.js 不浪費 CPU 周期並且保持高度可擴展。


process.nextTick() vs setImmediate()

這是一個雖小卻很重要的細節,但絕大多數人會忽略。

process.nextTick()

  • 執行當前函數之後立即
  • 運行在事件迴圈繼續之前
  • 如果濫用,可以阻擋 I/O

setImmediate()

  • 將在下一個迭代中執行(檢查階段)
  • 更安全且更可預測

→ 官方文件建議:

在大多數實際情況下優先使用setImmediate()


Node.js 如何處理千萬級請求

現在才是真正的问题.

傳統伺服器(每請求一個執行緒)

  • 每個請求 = 新的線程
  • 記憶體密集
  • 上下文切換開銷

Node.js 方法

  • 單一線程處理所有請求
  • 每個請求不建立線程
  • 使用非同步回調

實際發生的事:

  • 1000名用戶訪問伺服器
  • Node.js:

    • 註冊所有請求
    • 啟動非同步操作
    • 保持事件迴圈免於擁塞
  • 當回應回來:

    • 回調函數排隊
    • 事件迴圈執行它們

→ 結果:
高並發性與低資源使用


重要洞見:Node.js 適合用於 I/O 約束型工作

Node.js 在以下情況下表現出色:

  • 資料庫查詢
  • API 呼叫
  • 檔案系統操作
  • 串流
  • 實時應用程式(聊天、插座)

但…

不適合:

  • 重點 CPU 計算
  • 大型同步迴圈

因為:

阻擋事件迴圈 = 阻擋所有事情


常見的致命性能錯誤

1. 阻擋程式碼

while(true) {}

Enter fullscreen mode Exit fullscreen mode

→ 使整個伺服器凍結


2. 錯誤使用 process.nextTick()

  • 可能使事件迴圈匱乏資源
  • 阻止I/O執行

3. 在 API 中撰寫同步程式碼

fs.readFileSync()

Enter fullscreen mode Exit fullscreen mode

→ 避免在生產環境中使用


如果您需要更多效能(擴展超過單一核心)

Node.js 是單線程的每個進程,但您可以透過以下方式進行擴展:

  • Cluster 模組
  • 工作線程
  • 負載均衡器

→ 這允許:

  • 多核心利用
  • 水平擴展

我的最終理解

經過官方 Node.js 文檔和實際開發應用後,這是我對它的理解:

  • Node.js 並非試圖一次做所有事情
  • 它試圖 永不阻塞

事件迴圈只是一個聰明的協調者:

  • 它執行已準備好的任務
  • 跳過正在等待的任務
  • 保持系統運行

→ 這就是原因:

Node.js 可以處理成千上萬的並發請求 — 不是透過平行執行,而是透過 高效的排程和非阻塞性設計


結論

如果我必須用一句話總結:

Node.js之所以可擴展,不是因為它處理工作的速度快,而是因為它在避免不必要的等待

一旦這種思維模式啟動,Node.js架構的各個方面就開始顯得合理。