cover

概念概覽

flowchart TD
    BP[Browser Process 主進程] --> UI[UI 介面]
    BP --> NET[網路請求]
    BP --> STR[儲存管理]
    BP --> RP1[Renderer Process Tab 1]
    BP --> RP2[Renderer Process Tab 2]
    BP --> GPU[GPU Process]
    RP1 --> MT[主執行緒 JS/DOM/CSS]
    RP1 --> CT[合成執行緒]
    RP1 --> RT[光柵化執行緒]
    MT --> EL[Event Loop]
    EL --> MIC[Microtask Queue]
    EL --> MAC[Macrotask Queue]

瀏覽器的多進程架構

你可能會想:「我是前端工程師,幹嘛要了解瀏覽器內部怎麼運作?」但其實,你遇到的很多效能問題——頁面卡頓、動畫不流暢、JavaScript 阻塞畫面——都跟瀏覽器的底層機制有關。搞懂它,你才知道為什麼 transformtop/left 效能好、為什麼 setTimeout(fn, 0) 不是真的零延遲、為什麼一個分頁掛了不會影響其他分頁。

現代瀏覽器(如 Chrome)採用多進程架構:

進程職責
Browser Process主進程,管理 UI、網路、儲存
Renderer Process渲染網頁,每個 Tab 獨立進程
GPU Process處理 GPU 相關任務
Plugin Process執行瀏覽器外掛
Extension Process執行擴充功能
┌─────────────────────────────────────────────┐
│              Browser Process                 │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐       │
│  │  UI     │ │ Network │ │ Storage │       │
│  └─────────┘ └─────────┘ └─────────┘       │
└─────────────────────────────────────────────┘
        │           │           │
        ▼           ▼           ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│  Renderer   │ │  Renderer   │ │  Renderer   │
│  (Tab 1)    │ │  (Tab 2)    │ │  (Tab 3)    │
└─────────────┘ └─────────────┘ └─────────────┘

Renderer Process 的組成

每個渲染進程包含多個執行緒:

1. 主執行緒(Main Thread)

  • 解析 HTML、CSS
  • 執行 JavaScript
  • 計算樣式和佈局
  • 單執行緒,這就是為什麼 JS 會阻塞渲染

2. 合成執行緒(Compositor Thread)

  • 處理圖層合成
  • 處理滾動等不需要主執行緒的操作

3. 光柵化執行緒(Raster Thread)

  • 將向量圖形轉換為像素

JavaScript 引擎

V8 引擎(Chrome)

JavaScript 程式碼
      ↓
┌─────────────────┐
│   Parser        │  解析成 AST
└────────┬────────┘
         ↓
┌─────────────────┐
│   Ignition      │  解譯器,產生 Bytecode
└────────┬────────┘
         ↓
┌─────────────────┐
│   TurboFan      │  JIT 編譯器,優化熱點程式碼
└────────┬────────┘
         ↓
   機器碼

記憶體管理

  • Stack:存放基本類型、函數呼叫
  • Heap:存放物件、陣列
  • 垃圾回收:自動釋放不再使用的記憶體

了解了瀏覽器的多進程架構和 JS 引擎之後,還有一個關鍵問題:JavaScript 明明是單執行緒,那它是怎麼處理非同步操作的?答案就是事件循環。

事件循環(Event Loop)

JavaScript 是單執行緒,透過事件循環處理非同步操作:

┌─────────────────────────────────────────────┐
│                 Call Stack                   │
│  ┌─────────────────────────────────────┐    │
│  │                                     │    │
│  └─────────────────────────────────────┘    │
└─────────────────────────────────────────────┘
                    ↑
                    │ 執行
                    │
┌─────────────────────────────────────────────┐
│               Event Loop                     │
│                                              │
│  ┌────────────────────┐  ┌────────────────┐ │
│  │  Microtask Queue   │  │  Macrotask     │ │
│  │  (Promise, queueM) │  │  (setTimeout)  │ │
│  └────────────────────┘  └────────────────┘ │
└─────────────────────────────────────────────┘

執行順序

  1. 執行同步程式碼(Call Stack)
  2. 清空 Microtask Queue(Promise.then、queueMicrotask)
  3. 執行一個 Macrotask(setTimeout、setInterval)
  4. 重複 2-3
console.log('1');  // 同步
 
setTimeout(() => {
  console.log('2');  // Macrotask
}, 0);
 
Promise.resolve().then(() => {
  console.log('3');  // Microtask
});
 
console.log('4');  // 同步
 
// 輸出順序:1, 4, 3, 2

渲染管線(Rendering Pipeline)

JavaScript → Style → Layout → Paint → Composite
    │          │        │        │         │
    │          │        │        │         └─ 合成圖層
    │          │        │        └─ 繪製像素
    │          │        └─ 計算位置大小
    │          └─ 計算最終樣式
    └─ 可能修改 DOM

重排(Reflow)vs 重繪(Repaint)

類型觸發條件效能影響
重排改變幾何屬性(寬高、位置)高(需重新計算佈局)
重繪改變外觀(顏色、背景)中(只需重新繪製)
合成transform、opacity低(只在 GPU 處理)

效能優化

// ❌ 多次重排
element.style.width = '100px';
element.style.height = '100px';
element.style.left = '10px';
 
// ✅ 使用 class 一次修改
element.classList.add('new-style');
 
// ✅ 使用 transform 代替位置改變
element.style.transform = 'translateX(10px)';

Web APIs

瀏覽器提供的 API,由瀏覽器執行緒處理:

  • DOM API:操作網頁元素
  • Fetch API:網路請求
  • Timer API:setTimeout、setInterval
  • Storage API:localStorage、sessionStorage
  • Canvas/WebGL:圖形繪製
  • Web Workers:背景執行緒
// Web Worker 範例 - 不阻塞主執行緒
const worker = new Worker('worker.js');
 
worker.postMessage({ data: heavyData });
 
worker.onmessage = (e) => {
  console.log('計算結果:', e.data);
};

延伸閱讀

Inside look at modern web browser JavaScript Visualized: Event Loop 瀏覽器發出request後經歷了什麼 JavaScript