虚拟列表滚动优化
虚拟列表滚动优化方案。
虚拟列表滚动优化
- 一般情况下虚拟列表滚动都是设置固定高度,滚动时通过计算当前可见区域的索引范围,只渲染可见区域的项,避免渲染所有项,提高性能。 但是在有些情况下会有列表的item 是动态高度的情况,比如列表项根据内容长度自动调整高度。
- 设置缓冲区,在用户滚动过快的情况下,偶尔会出现白屏闪烁的显现
动态高度需要注意的细节
注意点:
- 如何获取列表项的真实高度
- 和列表项的高度相关的计算应该如何计算
- 列表的渲染是否会发生变化
我刚开始的第一个方案是将列表的高度放在数组中,但是存在问题,如果列表项的高度不在设置的范围内,会导致渲染错误。 后来思考,将列表先渲染到屏幕外,对其高度进行缓存,然后再将其渲染到可见区域,但这样也不好,预先渲染存在性能问题,会导致渲染成本翻倍。
最终采用,预估高度先渲染的的方案, 先创建一个预估高度的列表项。先按照预估值渲染,有了真实高度之后,再将其更新到缓存列表中 需要注意索引,
白屏闪烁
产生的原因: 用户滚动过快,没有给新列表项的渲染足够的时间,于是在原来的技术上增加一个缓存区,这样整个渲染区域是由可视区域+缓存区组成。
长列表常见解决方案
除了虚拟列表,长列表的优化方案 长列表的痛点: 渲染耗时,性能底下,页面卡顿
早起有基于时间分片的方案: 使用 requestAnimationFrame,requestIdleCallback这些浏览器提供的API, 由浏览器来决定执行的时机 将渲染任务分片,避免渲染耗时过长,导致页面卡顿。 大量数据被分为多次渲染,每次只渲染一个片段,每个片段处理完定量的数据之后,将主线程交还浏览器,从而解决页面卡顿的问题,但是时间分片只能解决卡顿问题, 分多个时间段来处理,渲染依然是耗时的,并可有大量的 list DOM 存与页面中,性能依然底下。 (先使用)
还有哪些优化空间
前面虚拟列表仍然有优化空间,前面的方案使用监听scroll 事件来处理可见区域的数据更新,,但是有个问题,当滚动发生以后,scroll 事件会频繁触发,很多时候造成重复计算的问题,可能存在一定的性能浪费 其实这里可以使用 intersectionObserver 来替换监听scroll,相比scroll,intersectionObserver可以设置多个阈值来检测元素进入视口的不同程度,只有必要时才会触发渲染,而且监听回调也是异步的,不会阻塞主线程,从而提高性能。
还有一个问题是不定高的列表项中包含图片,高度由内容撑开,由于图拍呢发送网络请求,此时无法保证,在获取高度的时候,图片是否已经加载完成。从而导致计算不精确,这里可以使用 resizeObserver 来监听每个列表项的高度变化,当列表项的高度变化时,再更新缓存列表中对应项的高度。
缺点: intersectionObserver,resizeObserver 存在浏览器兼容问题