# 網頁效能最佳化原理
::: tip 🎯 核心問題
**為什麼你的網頁載入很慢，使用者還在瘋狂抱怨卡頓？** 這就像是問：為什麼餐廳上菜慢、顧客等得不耐煩？本章將帶你深入理解前端效能最佳化的核心概念，讓你的網頁「飛」起來。
:::

---

## 1. 要「效能最佳化」的動機

### 1.1 從能用到好用：效能最佳化的演變

十年前的網頁非常簡單，一個頁面可能就幾 KB，載入速度幾乎感覺不到延遲。那時的我們根本不需要考慮效能最佳化——因為問題還沒出現。

但現在完全不同了。現代網頁的複雜度呈指數級增長：一個電商首頁可能有幾十張高清圖片，一個社群平台可能同時載入上千條動態，一個管理後台可能包含幾十個互動元件。這些「豐富」的功能背後，是龐大的程式碼量和資源體積，如果不好好最佳化，使用者體驗就會一塌糊塗。

<div style="display: flex; gap: 20px; margin: 20px 0;">
<div style="flex: 1; padding: 16px; border: 1px solid #e4e7ed; border-radius: 12px;">

**👴 十年前的網頁**
- 單個頁面只有幾 KB 到幾十 KB
- 只有文字和少量圖片
- 使用者幾乎感覺不到載入延遲
- 不需要任何效能最佳化

</div>
<div style="flex: 1; padding: 16px; border: 1px solid #e4e7ed; border-radius: 12px;">

**🚀 現代的網頁**
- 單個頁面可能幾 MB 甚至更大
- 有高清圖片、影片、互動元件
- 載入慢、捲動卡、點擊反應遲鈍
- 必須做效能最佳化才能用

</div>
</div>

**這就是「效能最佳化」要解決的問題：讓使用者等待的時間更短，讓操作更流暢。**

### 1.2 案例：效能最佳化的必要性

你可能會說：「現在的網路這麼快，裝置這麼好，還需要考慮效能最佳化嗎？」讓我講一個真實的故事，你就會明白為什麼這些知識如此重要。

::: warning 小王的效能踩坑記
小王是一個剛入職的前端工程師，負責開發公司的電商首頁。他用了最新的 Vue 3、最流行的 UI 函式庫，功能做得非常完善，自己在公司的高效能電腦上測試時一切正常。

但上線後第二天，客服部門就炸鍋了——大量使用者投訴說「網站太卡了」、「圖片載入不出來」、「點擊按鈕半天沒反應」。小王打開自己的開發機測試，一切都很流暢啊，他完全不理解問題出在哪裡。

後來請師傅幫忙定位，師傅讓他用一台普通的筆記型電腦，連上普通的 4G 行動網路，然後再測試自己的網站。小王這才傻眼了：首頁載入要等十幾秒，捲動列表時卡得像 PPT，點擊按鈕後要等好幾秒才有反應。

原來小王的開發環境是頂配的 MacBook Pro + 千兆光纖，而大多數使用者用的是普通裝置 + 行動網路。他寫的程式碼裡有幾十張未壓縮的高清圖片，引入了整個 UI 函式庫但只用了幾個元件，還在渲染時做了大量同步計算。

解決方案其實不複雜：壓縮圖片、按需引入元件、把計算放到背景執行緒、使用虛擬列表。這樣改動之後，首頁載入時間從十幾秒變成了 2 秒，捲動也非常流暢，使用者投訴立刻消失了。

小王從此明白了一個道理：**不了解效能最佳化，你寫出來的程式碼在自己電腦上跑得飛快，但在使用者裝置上可能根本沒法用。**
:::

::: info 💡 核心啟示
效能最佳化不是可選項，而是必備技能。你要站在使用者的視角思考問題——他們用的是普通裝置、普通網路，如果你的程式碼在他們裝置上跑不動，那就說明你需要最佳化了。
:::

---

## 2. 核心概念：載入、渲染、互動

::: tip 🤔 這些概念和效能有什麼關係？
載入、渲染、互動就是使用者存取網頁的三個核心環節，每個環節都可能成為效能瓶頸。

當使用者存取你的網頁時，會依次經歷：
1. **載入** → 把 HTML/CSS/JS/圖片 從伺服器下載到瀏覽器
2. **渲染** → 把下載的內容「畫」成使用者能看到的頁面
3. **互動** → 回應使用者的點擊、捲動等操作

所以，**效能最佳化就是讓這三個環節都快起來**。理解它們，你才能知道效能瓶頸出在哪裡，該用什麼方法最佳化。
:::

在深入學習具體最佳化技巧之前，我們需要先搞清楚這幾個核心概念。為了幫助你更好地理解，我們用餐廳的比喻來類比它們之間的關係。

### 2.1 用餐廳比喻理解三個環節

想像你去一家餐廳吃飯，這個過程和存取網頁驚人地相似：

| 環節 | 🍽️ 餐廳比喻 | 實際作用 | 具體例子 |
|------|-------------|----------|----------|
| **載入** | 把食材從倉庫運送到廚房 | 把 HTML/CSS/JS/圖片 從伺服器下載到瀏覽器 | 使用者打開網頁，瀏覽器開始下載各種資源 |
| **渲染** | 廚師把食材加工成菜餚 | 瀏覽器把程式碼轉換成使用者能看到的頁面 | 瀏覽器解析 HTML、計算佈局、繪製頁面 |
| **互動** | 服務生回應顧客的需求 | 瀏覽器回應點擊、捲動等操作 | 使用者點擊按鈕，頁面做出回饋 |

### 2.2 載入（Loading）：食材運送

載入是指把網頁所需的各種資源（HTML、CSS、JavaScript、圖片、字型等）從伺服器下載到瀏覽器的過程。這個過程就像把食材從倉庫運送到廚房，如果運送慢或者食材太多，廚房就得乾等著。

**為什麼載入會慢？** 主要有三個原因：首先，資源體積太大——一張未壓縮的高清圖片可能就有 5MB，相當於下載一本小說；其次，網路延遲——如果伺服器在國外，或者使用者用行動網路，每個請求都要等很久；最後，請求太多——瀏覽器同時下載的資源數量有限，太多資源就要排隊。

::: details 🔍 看看載入階段都做了什麼
當使用者在瀏覽器網址列輸入網址並按下 Enter 後，會依次發生：

1. **DNS 解析**：把網域名稱（如 `www.example.com`）轉換成 IP 位址（如 `192.168.1.1`），就像透過電話簿查詢餐廳地址
2. **TCP 連線**：瀏覽器和伺服器建立連線，就像打電話前要先撥號
3. **TLS 握手**：建立安全連線（HTTPS），就像確認對方身分
4. **請求資源**：瀏覽器向伺服器請求 HTML 檔案
5. **解析 HTML**：瀏覽器解析 HTML，發現需要 CSS、JS、圖片等資源，繼續請求
6. **下載資源**：把所有需要的資源下載到本地
7. **開始渲染**：下載完成後，開始渲染頁面

前面的 1-4 步叫「首字節時間」（TTFB），後面的 5-7 步是真正的資源下載時間。
:::

**常見的載入最佳化手段：**

- **壓縮資源**：把檔案變小（Gzip、Brotli 壓縮）
- **使用 CDN**：把檔案存在離使用者更近的伺服器上
- **延遲載入**：只載入使用者看得到的內容，剩下的等使用者捲動時再載入
- **程式碼分割**：把大檔案拆成小檔案，按需載入

### 2.3 渲染（Rendering）：廚師做菜

渲染是指瀏覽器把下載的 HTML、CSS、JavaScript 轉換成使用者能看到的頁面的過程。這個過程就像廚師把食材加工成菜餚，如果工序複雜、步驟多，上菜就會慢。

::: tip 📖 什麼是「渲染」？
你可能聽說過「渲染」這個詞，它到底是什麼？

**簡單來說，渲染就是把程式碼變成畫面的過程。**

瀏覽器要做的事情包括：
1. **解析 HTML** → 生成 DOM 樹（頁面的結構）
2. **解析 CSS** → 生成 CSSOM 樹（頁面的樣式）
3. **合併** → 生成渲染樹（結構和樣式的結合）
4. **佈局** → 計算每個元素的位置和大小
5. **繪製** → 把元素畫出來
6. **合成** → 把多個圖層合併成最終畫面

這個過程非常複雜，任何一個環節出問題，都會導致頁面卡頓。
:::

**為什麼渲染會慢？** 主要有兩個原因：首先，頁面太複雜——如果一個頁面有上萬個 DOM 節點，瀏覽器計算佈局和繪製就會非常耗時；其次，頻繁修改頁面——如果 JavaScript 程式碼頻繁修改 DOM，會導致瀏覽器反覆重新佈局和繪製，消耗大量效能。

::: details 📁 看看渲染階段都做了什麼
**渲染的完整流程**：

```
HTML (字串)
    ↓
[解析 HTML] → 生成 DOM 樹
    ↓
DOM 樹 (頁面結構)

CSS (樣式表)
    ↓
[解析 CSS] → 生成 CSSOM 樹
    ↓
CSSOM 樹 (頁面樣式)

DOM 樹 + CSSOM 樹
    ↓
[合併] → 生成渲染樹
    ↓
渲染樹 (要渲染的元素)
    ↓
[佈局 Layout] → 計算每個元素的位置和大小
    ↓
[繪製 Paint] → 填充顏色、繪製文字
    ↓
[合成 Composite] → 合併多個圖層
    ↓
最終畫面
```

**關鍵渲染路徑（Critical Rendering Path）**：瀏覽器要盡快把第一屏內容渲染出來，讓使用者覺得「網站很快」。這叫「關鍵渲染路徑最佳化」。
:::

👇 **動手看看**：
下面這個演示展示了瀏覽器是如何渲染頁面的。點擊「下一步」，觀察渲染的各個階段：

<PerformanceOverviewDemo />

**常見的渲染最佳化手段：**

- **減少重排和重繪**：避免頻繁修改 DOM，使用 `transform` 和 `opacity` 代替 `top` 和 `width`
- **虛擬列表**：只渲染可見區域的內容，大量資料時效能提升明顯
- **CSS 動畫**：用 CSS 動畫代替 JavaScript 動畫，效能更好

### 2.4 互動（Interaction）：服務生回應

互動是指瀏覽器回應使用者操作（點擊、捲動、輸入等）的過程。這個過程就像服務生回應顧客的需求，如果服務生忙不過來，顧客就得等。

**為什麼互動會卡？** 主要原因是**主執行緒被阻塞了**。瀏覽器的 JavaScript 是單執行緒的，如果程式碼在執行複雜的計算，就沒法回應使用者的操作，導致頁面卡頓。

::: tip 🤔 什麼是「主執行緒」？
瀏覽器有多個執行緒，但負責執行 JavaScript、渲染頁面、回應使用者操作的只有一個——**主執行緒**。

你可以把主執行緒想像成一個**忙碌的服務生**，他要做很多事情：
- 執行 JavaScript 程式碼（計算資料、呼叫 API）
- 渲染頁面（佈局、繪製）
- 回應使用者操作（點擊按鈕、捲動頁面）

問題來了：**他只有一個人**。如果他在執行複雜的 JavaScript 計算（比如處理一萬條資料），這時候使用者點擊了按鈕，他是沒法立即回應的，必須等計算完才行。這就是**卡頓**的根源。

**解決方案**：
- 把複雜的計算放到 Web Worker（背景執行緒）
- 使用時間切片，把大任務拆成小任務
- 避免同步的複雜操作，改用非同步
:::

👇 **動手試試看**：
下面這個演示對比了同步計算和 Web Worker 的區別。點擊「開始計算」，觀察頁面是否卡頓：

<PerformanceMetricsDemo />

**常見的互動最佳化手段：**

- **防抖和節流**：限制事件的觸發頻率（比如捲動事件、輸入事件）
- **Web Worker**：把複雜計算放到背景執行緒，不阻塞主執行緒
- **時間切片**：把大任務拆成小任務，讓瀏覽器有機會回應使用者操作

---

## 3. 實戰：一個團隊的效能最佳化演進之路

講了這麼多概念，讓我們看一個真實的案例：某新創公司是如何從「完全沒考慮效能」一步步進化到「系統化效能最佳化」的。透過這個案例，你會更直觀地理解效能最佳化到底解決了什麼問題。

### 3.1 演進的全景圖

下面這張表展示了效能最佳化的四個階段，你可以看到最佳化手段、工具、指標是如何一步步進化的：

| 階段 | 最佳化手段 | 監控工具 | 核心指標 | 核心變化 |
|------|---------|---------|---------|----------|
| **階段一：原始時代** | 無（沒考慮） | 無（憑感覺） | 無 | 完全沒效能意識，能跑就行 |
| **階段二：手動最佳化** | 壓縮圖片、減少請求 | 瀏覽器 Network 面板 | 頁面載入時間 | 開始有意識，但方法原始 |
| **階段三：系統化最佳化** | 程式碼分割、延遲載入、虛擬列表 | Lighthouse、Performance 面板 | FCP、LCP、TBT | 用專業工具，有明確的最佳化目標 |
| **階段四：持續最佳化** | 效能預算、CI/CD 檢查 | RUM、Lighthouse CI | INP、CLS、全鏈路監控 | 把效能納入開發流程 |

::: tip 📊 從表格中你能看到什麼？
讓我們逐行解讀這張表：

**階段一 → 階段二**：從「沒意識」到「有意識」。這是關鍵的一步——開發者開始意識到效能是個問題，並且嘗試最佳化。但最佳化手段比較原始，主要靠感覺和經驗。

**階段二 → 階段三**：從「手動」到「系統化」。這是質的飛躍——開始使用專業工具（Lighthouse、Performance 面板）來診斷效能問題，用科學的方法（程式碼分割、延遲載入）來最佳化，而不是憑感覺。

**階段三 → 階段四**：從「一次性最佳化」到「持續最佳化」。當效能最佳化成為開發流程的一部分後，就需要建立監控體系（RUM、真實使用者監控），在開發階段就設定效能預算，防止退化。

**總結一下**：效能最佳化演進不只是「用了更多技術」，而是**整個思維方式的升級**——從被動回應到主動預防，從憑感覺到資料驅動，從單次最佳化到持續改進。
:::

### 3.2 階段一：原始時代——完全沒考慮

為什麼叫「原始時代」？因為這個階段完全沒考慮效能問題——能跑就行。團隊只有 3 個人，做一個簡單的企業官網，專案很小，看起來沒什麼問題。

但隨著專案變大、使用者增多，問題開始暴露出來。

**開發方式**：
- **最佳化手段**：無，直接開發，沒考慮效能
- **監控工具**：無，憑感覺判斷快慢
- **核心指標**：無

**這個階段的特點**：
- ✅ **優點**：開發快，沒有額外的學習成本
- ❌ **缺點**：使用者體驗差，網速慢時根本沒法用

::: details 查看當時的問題
**遇到的具體問題**：

1. **圖片太大**：產品經理上傳了一張 5MB 的首頁 Banner 圖，行動網路使用者打開網頁要等 1 分鐘
2. **沒有壓縮**：CSS 和 JS 檔案完全沒有壓縮，體積是壓縮後的 3 倍
3. **沒有快取**：每次存取都要重新下載所有資源，老使用者也要等
4. **同步載入**：所有 JS 檔案都在 `<head>` 中同步載入，阻塞頁面渲染

**使用者的回饋**：
- 「你們網站怎麼打不開？」
- 「圖片半天載入不出來，就是空白」
- 「點擊按鈕沒反應，是不是網站壞了？」

**當時的臨時解決方案**：
```html
<!-- 用 loading 遮罩「欺騙」使用者 -->
<div id="loading">載入中...</div>
<script>
  // 頁面載入完成後才移除遮罩
  window.onload = function() {
    document.getElementById('loading').style.display = 'none'
  }
</script>
```

這完全是在「自欺欺人」——頁面還是很慢，只是使用者看不到而已。
:::

### 3.3 階段二：手動最佳化——開始有意識

原始時代的問題累積到一定程度，團隊終於決定開始做效能最佳化。這是一個重要的轉折點——從「完全不考慮」到「有意識地最佳化」。

但這個階段的最佳化比較原始，主要靠壓縮圖片、合併檔案等簡單手段。

**開發方式**：
- **最佳化手段**：手動壓縮圖片、合併 CSS/JS 檔案、減少 HTTP 請求
- **監控工具**：瀏覽器 Network 面板、簡單的計時日誌
- **核心指標**：頁面載入時間（手動用碼錶計時）

**這個階段的特點**：
- ✅ **優點**：有明顯改善，使用者不再瘋狂投訴
- ❌ **缺點**：最佳化不系統，容易反覆，缺少量化指標

::: details 查看手動最佳化的具體做法
**手動最佳化手段**：

1. **手動壓縮圖片**：
   - 用 Photoshop 把每張圖片手動「另存為 Web 格式」
   - 把 PNG 轉 JPEG（有損壓縮，但體積小很多）
   - 縮小圖片尺寸（比如 2000px 寬的圖縮小到 800px）

2. **手動合併檔案**：
   ```html
   <!-- 最佳化前：10 個 JS 檔案 = 10 個請求 -->
   <script src="utils.js"></script>
   <script src="api.js"></script>
   <script src="component-a.js"></script>
   <script src="component-b.js"></script>
   ...（還有 6 個）

   <!-- 最佳化後：1 個合併的 JS 檔案 = 1 個請求 -->
   <script src="all.js"></script>
   ```

3. **把 CSS/JS 移到頁面底部**：
   ```html
   <body>
     <!-- 頁面內容 -->
     <h1>歡迎訪問</h1>

     <!-- 最佳化：把 CSS/JS 放在最後 -->
     <link rel="stylesheet" href="style.css">
     <script src="app.js"></script>
   </body>
   ```

**帶來的改善**：
- 圖片體積從 5MB 減小到 500KB（減少 90%）
- HTTP 請求數從 30 個減少到 5 個
- 頁面載入時間從 30 秒減少到 8 秒

**新的痛點**：
1. **手動工作量大**：每次更新都要手動壓縮圖片、合併檔案
2. **容易忘記**：新人不知道要最佳化，直接上傳原圖
3. **缺少量化**：只知道「快了一些」，但不知道具體快多少
:::

### 3.4 階段三：系統化最佳化——用工具和視覺化資訊編碼原則

階段二的問題（手動工作量大、缺少量化）困擾了團隊很久。直到後來，團隊發現了 Lighthouse、Performance 面板等專業工具，進入了系統化最佳化時代。

這個階段的核心是**用資料驅動最佳化**——先用工具診斷問題，找到效能瓶頸，再有針對性地最佳化。

**開發方式**：
- **最佳化手段**：程式碼分割、延遲載入、虛擬列表、圖片自動壓縮
- **監控工具**：Lighthouse、Chrome Performance 面板、WebPageTest
- **核心指標**：FCP（首屏時間）、LCP（最大內容繪製）、TBT（總阻塞時間）

::: details 系統化最佳化的具體做法
**使用 Lighthouse 診斷問題**：

Lighthouse 是 Google 開發的自動化效能測試工具，可以給出全面的效能報告和最佳化建議。

```bash
# 使用 Lighthouse 測試網頁
lighthouse https://www.example.com --view
```

Lighthouse 會給出：
- **效能評分**（0-100 分）
- **核心指標**（FCP、LCP、CLS、TBT、INP）
- **最佳化建議**（比如「啟用文字壓縮」、「移除未使用的 JavaScript」）

**關鍵指標解讀**：

| 指標 | 全稱 | 含義 | 理想值 |
|------|------|------|--------|
| **FCP** | First Contentful Paint | 首次內容繪製時間（使用者看到第一塊內容的時間） | <1.8s |
| **LCP** | Largest Contentful Paint | 最大內容繪製時間（主要內容載入完成的時間） | <2.5s |
| **TBT** | Total Blocking Time | 總阻塞時間（主執行緒被阻塞的總時間） | <200ms |
| **CLS** | Cumulative Layout Shift | 累積佈局偏移（頁面元素亂跳的程度） | <0.1 |

:::

**這個階段的特點**：
- ✅ **優點**：最佳化有針對性，效果好，有量化指標
- ❌ **缺點**：需要學習工具和指標，有一定門檻

::: details 查看系統化最佳化的具體技術
**1. 程式碼分割（Code Splitting）**：

把大檔案拆成小檔案，按需載入。比如使用者訪問首頁時，只載入首頁需要的程式碼，等到點擊「關於我們」時，再去載入關於頁面的程式碼。

```js
// 最佳化前：所有程式碼都在一個檔案，一次性載入
import About from './views/About.vue'
import Contact from './views/Contact.vue'
// ... 還有 10 個頁面

// 最佳化後：延遲載入，訪問時才載入
const About = () => import('./views/About.vue')
const Contact = () => import('./views/Contact.vue')
```

**效果**：首頁載入的程式碼量減少 70%，首屏時間從 5 秒降到 1.5 秒。

**2. 圖片延遲載入（Lazy Loading）**：

只載入使用者看得到的圖片，捲動到可視區域時再載入其他圖片。

```html
<!-- 現代瀏覽器支援原生的延遲載入 -->
<img src="placeholder.jpg" data-src="real-image.jpg" loading="lazy" />
```

**效果**：首頁載入的圖片數量從 20 張減少到 3 張，節省 80% 的頻寬。

**3. 虛擬列表（Virtual Scrolling）**：

如果要渲染 10,000 條資料，不要真的建立 10,000 個 DOM 節點，而是只渲染可見區域的 20 條，捲動時動態替換。

```vue
<!-- 使用 vue-virtual-scroller 元件 -->
<RecycleScroller
  :items="items"
  :item-size="50"
  key-field="id"
>
  <template #default="{ item }">
    <div>{{ item.name }}</div>
  </template>
</RecycleScroller>
```

**效果**：10,000 條資料從「卡死」變成「流暢捲動」，記憶體佔用減少 95%。
:::

### 3.5 階段四：持續最佳化——把效能納入開發流程

當工具和方法成熟後，團隊開始關注更深層次的問題：如何防止效能退化？如何讓效能成為開發流程的一部分？

這個階段的核心是**建立效能監控和預算體系**——不是上線後再最佳化，而是在開發階段就預防效能問題。

**開發方式**：
- **最佳化手段**：效能預算（Performance Budget）、Lighthouse CI、真實使用者監控（RUM）
- **監控工具**：Lighthouse CI、WebPageTest API、Google Analytics
- **核心指標**：INP（互動延遲）、CLS（佈局偏移）、全鏈路監控

::: details 持續最佳化的具體做法
**1. 設定效能預算**：

在打包配置中設定限制，超過就報錯，防止「無意中引入大檔案」。

```js
// vite.config.js
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        // 限制單個檔案不超過 200KB
        chunkFileNames: 'js/[name]-[hash].js',
      }
    },
    // 超過 200KB 時發出警告
    chunkSizeWarningLimit: 200
  }
})
```

**2. Lighthouse CI**：

每次提交程式碼時，自動執行 Lighthouse 測試，如果效能分數下降，就阻止合併。

```yaml
# .github/workflows/lighthouse.yml
name: Lighthouse CI
on: [pull_request]
jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run Lighthouse CI
        uses: treosh/lighthouse-ci-action@v9
        with:
          urls: |
            https://staging.example.com
          budgetPath: ./budget.json
```

**3. 真實使用者監控（RUM）**：

在真實使用者瀏覽器中收集效能資料，而不是只在開發環境測試。

```js
// 傳送效能資料到伺服器
const perfData = performance.getEntriesByType('navigation')[0]
const lcp = performance.getEntriesByType('largest-contentful-paint')[0]

fetch('/api/perf', {
  method: 'POST',
  body: JSON.stringify({
    fcp: perfData.loadEventEnd - perfData.fetchStart,
    lcp: lcp.renderTime || lcp.loadTime,
    url: window.location.href
  })
})
```

**效果**：
- 能及時發現效能退化（比如某次提交導致 LCP 從 2 秒變成 5 秒）
- 能了解真實使用者的體驗（而不是開發環境的「理想狀態」）
- 能針對性地最佳化最慢的那 10% 使用者
:::

**這個階段會做什麼？**

1. **效能預算**：限制檔案大小、請求數量，超過就報警
2. **CI/CD 檢查**：每次提交程式碼自動測試效能，退化就阻止合併
3. **真實使用者監控**：收集真實使用者的效能資料，持續改進
4. **定期效能報告**：每週/每月生成效能報告，追蹤趨勢

---

## 4. 常見效能瓶頸與解決方案

講了這麼多理論，讓我們看看實際開發中最常見的效能問題，以及如何解決。

### 4.1 圖片載入慢

**問題表現**：圖片半天載入不出來，或者載入過程中頁面跳動。

**原因**：
- 圖片體積太大（高清原圖）
- 圖片尺寸太大（2000px 寬的圖顯示為 200px）
- 沒有延遲載入（一次性載入所有圖片）

**解決方案**：

1. **使用現代圖片格式**（WebP、AVIF）：

```html
<!-- 現代：WebP 格式，體積小 30-70% -->
<picture>
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="圖片">
</picture>
```

2. **響應式圖片**（根據裝置大小載入不同尺寸）：

```html
<!-- 小裝置載入小圖，大裝置載入大圖 -->
<img
  src="image-800.jpg"
  srcset="image-400.jpg 400w,
          image-800.jpg 800w,
          image-1200.jpg 1200w"
  sizes="(max-width: 600px) 400px,
         (max-width: 1200px) 800px,
         1200px"
  alt="響應式圖片">
```

3. **延遲載入**（使用者捲動到時再載入）：

```html
<!-- 現代：原生延遲載入 -->
<img src="placeholder.jpg" data-src="real-image.jpg" loading="lazy" />
```

👇 **動手試試看**：
下面這個演示對比了延遲載入和不延遲載入的區別。觀察網路請求：

<ImageOptimizationDemo />

### 4.2 首屏載入慢

**問題表現**：使用者打開網頁，白屏時間很長。

**原因**：
- 載入了太多不必要的程式碼
- 關鍵渲染路徑被阻塞
- 沒有做程式碼分割

**解決方案**：

1. **程式碼分割**（Code Splitting）：

```js
// 路由延遲載入：訪問時才載入
const routes = [
  {
    path: '/about',
    component: () => import('./views/About.vue')  // 訪問 /about 時才載入
  }
]
```

2. **預載入關鍵資源**（Preload）：

```html
<!-- 提前告知瀏覽器：這些資源很重要，優先載入 -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="hero-image.jpg" as="image">
```

3. **內聯關鍵 CSS**：

```html
<!-- 把首屏需要的 CSS 直接內嵌在 HTML 中 -->
<style>
  /* 首屏關鍵樣式 */
  .hero { background: #000; color: #fff; }
</style>
```

### 4.3 捲動卡頓

**問題表現**：頁面捲動時一卡一卡的，不流暢。

**原因**：
- 渲染了太多 DOM 節點（比如 10,000 條資料）
- 捲動事件監聽器中有複雜計算
- 頻繁觸發佈局計算

**解決方案**：

1. **虛擬列表**（Virtual Scrolling）：

```vue
<!-- 只渲染可見區域的內容 -->
<RecycleScroller
  :items="10000"
  :item-size="50"
>
  <template #default="{ item }">
    <div>{{ item.name }}</div>
  </template>
</RecycleScroller>
```

👇 **動手看看**：
下面這個演示對比了普通列表和虛擬列表的效能差異：

<VirtualScrollingDemo />

2. **節流捲動事件**（Throttle）：

```js
// 限制捲動事件的觸發頻率（最多每 100ms 觸發一次）
const throttledScroll = throttle(() => {
  updatePosition()
}, 100)

window.addEventListener('scroll', throttledScroll)
```

3. **使用 CSS `will-change`**：

```css
/* 提前告知瀏覽器：這個元素會變化，請做好準備 */
.scroll-container {
  will-change: transform;
}
```

### 4.4 點擊反應慢

**問題表現**：點擊按鈕後，要等好幾秒才有反應。

**原因**：
- 點擊事件處理器中有複雜計算（阻塞主執行緒）
- 沒有使用防抖（使用者快速點擊多次，觸發多次計算）

**解決方案**：

1. **防抖點擊事件**（Debounce）：

```js
// 使用者停止點擊 300ms 後才執行
const debouncedClick = debounce(() => {
  submitForm()
}, 300)

button.addEventListener('click', debouncedClick)
```

2. **使用 Web Worker**（把計算放到背景執行緒）：

```js
// 主執行緒
const worker = new Worker('calculator.js')
button.addEventListener('click', () => {
  worker.postMessage({ data: largeData })
})

worker.onmessage = (e) => {
  // 計算完成，顯示結果
  showResult(e.data.result)
}

// calculator.js (Worker 執行緒)
self.onmessage = (e) => {
  const result = heavyCalculation(e.data.data)
  self.postMessage({ result })
}
```

---

## 5. 效能監控工具

效能最佳化不是一次性工作，需要持續監控。下面介紹常用的工具。

### 5.1 瀏覽器開發者工具

**Chrome DevTools** 是最常用的效能分析工具：

- **Network 面板**：查看資源載入情況
- **Performance 面板**：分析執行時效能（FPS、主執行緒活動）
- **Lighthouse**：一鍵生成效能報告

::: tip 如何使用 Performance 面板
1. 打開 Chrome DevTools（F12）
2. 切換到 Performance 面板
3. 點擊「Record」按鈕
4. 操作網頁（捲動、點擊等）
5. 點擊「Stop」停止錄製
6. 分析結果：看 FPS（幀率）、主執行緒活動、長任務等
:::

### 5.2 Lighthouse

**Lighthouse** 是 Google 開發的自動化效能測試工具：

```bash
# 命令列使用
lighthouse https://www.example.com --view

# 或者在 Chrome DevTools 中使用
# 打開 DevTools → Lighthouse → 點擊 "Analyze page load"
```

Lighthouse 會給出：
- 效能評分（0-100 分）
- 核心指標（FCP、LCP、CLS、TBT、INP）
- 最佳化建議（按影響排序）

### 5.3 WebPageTest

**WebPageTest** 是線上效能測試工具，可以從多個地點、多種裝置測試：

```bash
# 訪問 https://www.webpagetest.org
# 輸入網址，選擇測試地點和裝置，點擊 "Start Test"
```

WebPageTest 會給出：
- 瀑布圖（Waterfall）：每個資源載入的時間線
- 影片對比：最佳化前後的載入過程影片
- 最佳化建議

---

## 6. 效能最佳化清單

下面是一個實用的效能最佳化清單，你可以按照這個順序最佳化你的網頁：

### 6.1 載入最佳化

- ✅ **壓縮圖片**：使用 WebP 格式，壓縮品質 80-85%
- ✅ **響應式圖片**：根據裝置大小載入不同尺寸的圖片
- ✅ **延遲載入**：圖片和元件延遲載入，只載入可見內容
- ✅ **程式碼分割**：按路由分割程式碼，按需載入
- ✅ **壓縮程式碼**：啟用 Gzip/Brotli 壓縮
- ✅ **使用 CDN**：把靜態資源放到 CDN，加速下載
- ✅ **預載入關鍵資源**：使用 `<link rel="preload">`

### 6.2 渲染最佳化

- ✅ **減少重排重繪**：使用 `transform` 和 `opacity` 代替 `top` 和 `width`
- ✅ **虛擬列表**：大量資料時使用虛擬捲動
- ✅ **CSS 動畫**：優先使用 CSS 動畫，而不是 JavaScript 動畫
- ✅ **最佳化關鍵渲染路徑**：內聯關鍵 CSS，延遲載入非關鍵 CSS
- ✅ **避免 @import**：`@import` 會阻塞渲染，改用 `<link>`

### 6.3 互動最佳化

- ✅ **防抖和節流**：捲動、輸入、resize 事件使用防抖/節流
- ✅ **Web Worker**：複雜計算放到背景執行緒
- ✅ **時間切片**：大任務拆成小任務，避免長任務
- ✅ **避免同步佈局**：不要在迴圈中讀取佈局屬性（如 `offsetHeight`）

### 6.4 快取最佳化

- ✅ **HTTP 快取**：配置 Cache-Control 和 ETag
- ✅ **Service Worker**：快取靜態資源，實現離線訪問
- ✅ **LocalStorage**：快取 API 資料，減少請求
- ✅ **記憶體快取**：使用 `Map`/`Object` 快取計算結果

### 6.5 監控最佳化

- ✅ **Lighthouse CI**：每次提交程式碼自動測試效能
- ✅ **真實使用者監控**：收集真實使用者的效能資料
- ✅ **效能預算**：設定檔案大小限制，超過報警
- ✅ **定期效能報告**：每週/每月生成效能趨勢報告

---

## 7. 總結

讓我們用一張表格來回顧前端效能最佳化的核心概念：

| 概念 | 一句話解釋 | 解決的問題 | 常用手段 |
|------|-----------|-----------|----------|
| **載入最佳化** | 讓資源下載更快 | 首屏慢、等待時間長 | 壓縮圖片、CDN、程式碼分割、延遲載入 |
| **渲染最佳化** | 讓頁面「畫」得更快 | 捲動卡、點擊慢 | 虛擬列表、減少重排重繪、CSS 動畫 |
| **互動最佳化** | 讓回應更快 | 點擊沒反應、操作卡頓 | 防抖節流、Web Worker、時間切片 |
| **快取最佳化** | 避免重複下載 | 重複訪問慢 | HTTP 快取、Service Worker、LocalStorage |
| **監控最佳化** | 持續發現問題 | 效能退化 | Lighthouse、RUM、效能預算 |

::: info 寫在最後
效能最佳化是一個持續演進的話題，工具會變，但核心理念不變：**站在使用者的角度思考問題，讓等待時間更短、讓操作更流暢**。

理解了這些基本原理，無論技術如何更新換代，你都能快速上手、從容應對。

希望這篇文章能幫助你建立起對前端效能最佳化的整體認知。當你在實際專案中遇到效能問題時，能夠知道從哪裡入手、如何定位、怎樣解決。
:::