问题
渲染永远是网页运算中极度耗费性能的一块瓶颈之一,而在像是仪表板应用或是大量资料清单如社交媒体版面很容易会遇到前端渲染效率上的问题,通过“只渲染看得到的东西”来减少性能负担。这种模式通常称作 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 节点数(以降低内存或事件监听成本),真正的虚拟化仍然必要。
总结
使用虚拟化之前最好先思考真的有必要要渲染这么多元素到网页中吗?
- 能不能通过其他体验取代(分页、简化或取消渲染内容)
- 对于无障碍使用体验和 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