問題
渲染永遠是網頁運算中極度耗費效能的一塊瓶頸之一,而在像是儀表板應用或是大量資料清單如社群媒體版面很容易會遇到前端渲染效率上的問題,透過「只渲染看得到的東西」來減少效能負擔。這種模式通常稱作 List Virtualization(虛擬化看不到的東西)或 Windowing(只渲染視窗內的東西)。
用 List Virtualization 解決問題
當使用者滾動時,逐步刪除不在視窗內的項目,並在視窗內渲染新的項目。這樣可以:
- 大幅減少 DOM 節點數量與初次渲染要做的工作。
- 降低記憶體佔用與更新成本(因每次狀態變更要處理的元素變少)。
- 讓滾動與互動更順暢,尤其在資料量極大時非常明顯。
在實踐上對於被渲染的項目有兩種方式:
- 固定高度(Fixed size):每個項目高度相同。可以用簡單的數學計算(
scrollTop
/itemHeight
)。 - 動態高度(Variable size):項目高度不同,需要維護一張高度預估表加上緩存,實作複雜度較高但能處理更複雜場景。
單獨這項看似簡單的功能暗藏太多需要留意的實踐細節,可以參考的套件:
神奇的原生 CSS content-visibility
近期瀏覽器原生支援 content-visibility CSS 屬性,能讓瀏覽器「跳過」某個元素的 layout 與 paint 階段,直到該元素變得 可見或需要為止。
content-visibility 不是 把 DOM 節點移除,它是延後 layout 與 paint 作業;也就是 DOM 還存在,但瀏覽器可以選擇不做昂貴的動作。若真正需要減少 DOM 節點數(以降低記憶體或事件監聽成本),真正的 virtualization 仍然必要。
總結
使用 Virtualization 之前最好先思考真的有必要要渲染這麼多元素到網頁中嗎?
- 能不能透過其他體驗取代(分頁、簡化或取消渲染內容)
- 對於無障礙使用體驗上和 SEO 可能會有負面影響
它不是什麼必備的改善,但當問題進入到一定的規模,會需要認真考慮相關的問題。
延伸閱讀
- List Virtualization - patterns
- How Deep is Your DOM? - FRONTEND AT SCALE
- How large DOM sizes affect interactivity, and what you can do about it - web.dev
- content-visibility - mdn web docs
- Let’s Build a VIRTUALIZED LIST from Scratch in React.js - Raj talks
- Build your Own Virtual Scroll - Part I - adam klein