Haru Li
Frontend Developer
14 posts
捲到才載入:省的不只是資料,還有那個 JS 檔
列表一次只載一批、捲到底才取下一批——這是很常見的做法。但我做這個 demo 時想多做一件事:讓「程式碼也是資源」這件事看得見。
發想:兩種東西都可以延後
講到延遲載入,多數人想到的是資料:不要一次撈 10,000 筆,先撈 20 筆。
但還有一樣東西同樣佔流量,而且更早發生——渲染那些資料的元件程式碼本身。如果那個元件只有捲到列表底部才會用到,把它塞進首頁的主 bundle 就是讓每個訪客都先下載一份他可能永遠用不到的東西。
所以這個 demo 同時做兩件事:資料分批取,元件本身也用 React.lazy 切成獨立 chunk。
測試:打開 Network 分頁
demo 裡的框可以往下捲,新資料一批一批逐筆淡入。真正要看的在別的地方:
打開開發者工具的 Network 分頁,按重置再捲一次。 你會看到某個 .js 檔在第一次捲到底的那一瞬間才被請求——頁面剛載入時完全沒有抓它。
demo 上還會顯示「模組抵達耗時」,那是從發出請求到模組可用的實際毫秒數。
理解:Vite 的 code splitting
React.lazy 搭配動態 import(),Vite 在建置時看到這個語法,會把那個模組(以及它獨有的依賴)切成獨立的 chunk 檔。
const Row = lazy(() => import("./DataRow"));
這一行的意思不只是「晚點再 import」,而是告訴打包工具:這段程式碼不要放進主 bundle。
代價是那個檔案要多一次網路來回。所以它適合「不一定會用到」或「肯定不是第一眼看到」的東西,不適合首屏就要出現的元件——首屏元件用 lazy 只會多一次往返,還可能閃一下骨架畫面。
講解:這站上的一個反例
我自己的網站就有一個「不能用 lazy」的地方。
作品集是靜態預先渲染的,建置時會用 renderToString 把每一頁的 HTML 產生好。如果頁面元件用 React.lazy,renderToString 只會渲染出 Suspense 的 fallback,而不是真正的內容——瀏覽器接手 hydrate 時發現對不上,就報 React #419。
所以那些要 prerender 的頁面全部是同步 import 的,程式碼裡還特地留了註解說明原因,免得日後有人「順手最佳化」時把它改回 lazy。
延遲載入的前提是那段內容真的可以晚點出現。 需要出現在 HTML 裡的東西,就不能延後。
這個 demo 可以在 效能實驗室 自己操作。
