飯糰
ONIGIRI常駐監工
主樓2026-08-16
飯糰

Haru Li

前端工程師

發表 14 篇

·約 2 分鐘效能瀏覽器

一萬筆資料,只畫二十個節點

上一個 demo 講的是「不要一次載完」。這個講的是相反的一半:資料全都在記憶體裡了,但你不必全部畫出來。

發想:把兩件事分開

「列表很卡」通常會得到「用分頁或無限捲動」的建議。但那解的是資料量的問題。

有些情況資料本來就得全部在手上——要做排序、要算總計、要即時篩選。這時資料量沒得減,能減的是 DOM 節點數

我想做的 demo 是把這兩件事切乾淨:兩側資料完全一樣,都是 10,000 筆在記憶體裡,唯一的差別是畫幾個節點。

測試:按下去會卡一下

左邊「全部渲染」預設是不畫的,要按按鈕才開始——因為它真的會讓畫面卡住,直接畫出來會影響整頁的其他 demo。

按下去那一下的停頓,就是瀏覽器在算 10,000 個節點的版面。

右邊「虛擬捲動」只畫可視範圍的大約 20 筆,捲動時靠位移把它們對到正確位置。捲起來完全沒有那個停頓。

兩側都會顯示實際的 DOM 節點數與首次渲染耗時。

理解:為什麼是節點數

瀏覽器對每個元素都要做這些事:算樣式、算版面位置、可能還要繪製與合成。這些成本大致隨節點數線性成長,但版面計算在節點互相影響時會更貴。

10,000 對 20,節點數差 500 倍。這個差距不只出現在第一次渲染——它持續影響捲動的流暢度和記憶體用量,因為那些節點一直在那裡。

虛擬捲動的做法:

  1. 用一個高度等於「總筆數 × 單列高度」的容器撐出正確的捲軸
  2. 根據目前捲動位置算出「現在應該看到第幾筆到第幾筆」
  3. 只渲染那個範圍,用 transform 把它們推到對的位置

使用者看到的捲軸長度、捲動距離都跟真的畫一萬筆一樣,但 DOM 裡永遠只有二十幾個節點。

講解:什麼時候需要,什麼時候不用

需要的訊號:列表筆數是三位數以上、每一列的結構還不簡單(有圖、有多個欄位)、而且使用者真的會捲很長一段。

不需要的情況:幾十筆的列表。虛擬捲動要自己管高度、捲動位置、鍵盤操作與無障礙焦點,複雜度不低。為了 50 筆資料引進這些,是拿確定的維護成本換不確定的效能收益。

實務上多半不會自己實作,@tanstack/virtual 這類函式庫已經處理好變動列高、水平捲動、動態量測那些麻煩事。這個 demo 是手寫的,因為手寫才看得到機制。


這個 demo 可以在 效能實驗室 自己操作。

這裡的文章都寫在自家 repo 的 markdown 檔裡,發文就是新增一個檔案。

© 2026 HARU LI