打開 Facebook 首頁查看原始碼:HTML 極少,大量 ` 3. 瀏覽器**邊接收邊處理**: - 解析已到達 HTML → 構建部分 DOM - 平行下載 Pagelet 聲明的 CSS/JS (預加載) - 執行 onload 回調 → 將 Pagelet HTML 插入容器 → 初始化 JS 行為 4. 最後一塊 is_last=true 輸出,頁面完成 // 總耗時 ≈ max(後端並行查詢) + 首塊輸出延遲 + 前端增量渲染
每個 Pagelet 輸出一段內聯腳本:
<script>
big_pipe.onPageletArrive({
"id": "pagelet_welcome_box", // 容器 ID,對應頁面佔位符 <div id="pagelet_welcome_box"></div>
"phase": 1, // 階段,控制優先級/依賴順序
"is_last": false, // 是否最後一塊
"append": false, // true=追加,false=替換容器內容
"bootloadable": [], // 需啟動加載的資源 ID
"css": ["lDRwi", "eon+N"], // CSS 資源 ID 列表 (經編碼/映射)
"js": ["F+B8D", "IdQlc"], // JS 資源 ID 列表
"resource_map": [], // 資源映射表 (ID → URL, 類型, 永久快取等)
"requires": [], // 依賴的 JS 模組 ID
"provides": [], // 提供的 JS 模組 ID
"onload": [ // DOM 就緒後立即執行的腳本陣列
"window.__UIControllerRegistry['c4c13a3ed2dd1e0e349b72'] = new UIPagelet(...);"
],
"onafterload": [], // 頁面 onload 後執行
"onpagecache": [], // 頁面緩存恢復時執行
"onafterpagecache": [],
"refresh_pagelets": [], // 需刷新的其他 Pagelet ID
"invalidate_cache": [], // 失效緩存的 Pagelet ID
"content": { // 核心:HTML 字串
"pagelet_welcome_box": "<div id=\"c4c13a3ed2dd1e0e349b72\"><div class=\"UIImageBlock...\">...</div></div>"
},
"page_cache": true // 是否啟用頁面緩存 (Quickling)
});
</script>
<!-- 初始 HTML 框架中預留容器 -->
<div id="pagelet_welcome_box"><!-- 此處將被 Pagelet HTML 替換 --></div>
// onPageletArrive 內部邏輯簡化
onPageletArrive(pagelet) {
// 1. 下載並執行 css/js (Bootloader)
bootloader.loadResources(pagelet.css, pagelet.js, () => {
// 2. 容器替換/追加
const container = document.getElementById(pagelet.id);
if (container) {
if (pagelet.append) container.innerHTML += pagelet.content[pagelet.id];
else container.innerHTML = pagelet.content[pagelet.id];
}
// 3. 執行 onload 腳本 (初始化 UI 控制器)
pagelet.onload.forEach(script => eval(script));
});
}
| 技術棧 | 方案 | 關鍵點 |
|---|---|---|
| Node.js (Express/Koa) | 手寫中間件 `res.flush()` + 模板引擎流式渲染 | 需後端支援非阻塞並行查詢、流式模板 |
| React 18+ | renderToPipeableStream + ` | 元件級流式、選擇性水合、優先級調度 |
| Next.js 13+ (App Router) | Server Components + Streaming + `loading.js` | 約定式、自動代碼分割、Edge 部署 |
| Astro | Islands + `async` 組件 + 串流 | 默認靜態、互動島嶼按需水合 |
| Qwik | Resumability + 細粒度懶加載 | 零水合、HTML 序列化狀態、極速 TTI |
| PHP (Laravel/Symfony) | Laravel Stream Download / Symfony StreamedResponse | 配合 Octane/Swoole 協程並行查詢 |
| Java (Spring Boot) | WebFlux + Thymeleaf/FreeMarker 流式 | Reactive Streams 背壓控制 |
| Go | http.ResponseWriter (實現 Flusher) + template.Execute | 原生支援 flush、goroutine 並行 |
Facebook BigPipe 不僅是一項優化技術,更是一種**以用戶感知速度為核心、將頁面拆解為獨立可流式傳輸單元**的架構哲學。今日前端框架的流式渲染、島嶼架構、可恢復性,皆可溯源於此。理解其協議細節與工程權衡,是構建高性能現代 Web 應用的必修課。