分片渲染本质是用settimeout或requestanimationframe将js执行切片,避免主线程阻塞,从而缓解首次白屏但不解决滚动卡顿;它仅适用于静态大列表初始加载,需清空旧dom、批量插入、合理设块大小(50–200条),而滚动场景必须切换为虚拟列表。

分片渲染不是“减少DOM”,而是把卡顿拆成可感知的抖动
分片渲染在极长列表(比如10万条)下,性能提升有限,但能避免首次白屏——它不解决滚动卡顿,只缓解加载阻塞。核心是用setTimeout或requestAnimationFrame切开JS执行,让浏览器有机会paint和响应事件。
常见错误现象:滚动依然掉帧、内存缓慢上涨、DevTools里DOM节点数持续增加(没卸载旧块)。
- 每次渲染必须清空前一块内容,否则
container.innerHTML = ''或container.replaceChildren()漏掉就内存泄漏 - 块大小建议设为50–200条,太小导致频繁调度开销;太大又失去“切片”意义
- 不要用
for循环直接追加,改用DocumentFragment批量插入,否则每条appendChild都触发一次重排 - 滚动监听里调用分片逻辑?错——分片是加载策略,不是滚动响应策略;滚动时该用虚拟列表,不是继续分片
分片渲染 + 滚动监听 = 自找麻烦
有人在scroll事件里动态触发新分片加载,结果主线程被高频滚动事件+DOM操作双重拖垮。分片渲染只适合初始加载阶段,和滚动行为无关。
使用场景很窄:仅适用于「用户不立即滚动、但数据量大到无法整页渲染」的静态列表,比如后台导出预览页、日志归档页。
- 滚动监听必须加
{ passive: true },否则Chrome强制同步执行,哪怕你只是console.log也会卡帧 - 若真要支持滚动中加载,应切换为虚拟列表,而不是在
scroll里调renderChunk() -
requestAnimationFrame比setTimeout(0)更准,但别在RAF回调里做大量计算——它本意是“下一帧绘制前”,不是“下一秒执行”
固定高度虚拟列表才是极长列表的正解
当列表超过5000条,分片渲染已无意义;此时必须上虚拟列表。它把DOM节点数压到Math.ceil(container.clientHeight / itemHeight) + 2这个量级,比如可视区高600px、每项48px,最多只渲染15个li节点。
容易踩的坑全集中在容器设置上:
- 滚动容器必须有
height且非auto,min-height或flex: 1都不行,否则scrollTop不准 - 别用
margin-top推位置,必须用transform: translateY(),否则每帧都重排 - 所有项(含广告、分组标题)都要进
items数组,用type字段区分,硬插div会导致索引错位 - 撑高容器用
padding-bottom或额外div设height,不能靠内容自然撑开
为什么你写的分片渲染跑得比虚拟列表还慢
因为你在重复造轮子:手动管理块、计算偏移、拼HTML字符串、反复innerHTML赋值——这些操作本身就有开销。而成熟虚拟列表库(如react-window、vue-virtual-scroller)做了三件事:DOM复用池、二分查找定位、contain: layout paint提示浏览器跳过不可见区域绘制。
真实瓶颈不在“怎么渲染”,而在“怎么不让浏览器做多余的事”。分片渲染只是把锅从“一次炖糊”改成“分十次炒糊”,而虚拟列表是直接换灶具。
最常被忽略的点:没关掉开发者工具的“Disable cache”或“Throttling”,导致本地测试时网络请求拖慢整体感知——分片渲染的延迟,一半来自你以为的JS,另一半来自没关的Network面板。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











