关于"好奇移动端、桌面端是怎么实现列表控件渲染大量元素不卡顿的?"引申的问题

2024-07-24 10:06:18 +08:00
 Kinnikuman

上一个问题( https://www.v2ex.com/t/1059281 )我看已经讨论结束了,所以新开一个帖子来讨论下。

我的问题是,大量的列表会导致滑动卡顿吗?移动端有"回收,重用,缓存"这种策略,但如果不使用这种策略,而将大量的列表数据加载到内存中,滑动时候会卡顿吗?

我的理解是它们已经加载到内存中了,滑动只是将其展示出来,缺点是占用内存特别大。

如果使用了回收策略,只有屏幕展示的那几条列表会被加载到内存中,滑动出去的放到复用列表中,以供下次使用,这样可以节约大量内存,但在快速滚动刷新的列表中,这需要 cpu 进行大量的计算来刷新列表中的数据吧?

所以我觉得,如果不使用回收策略,那么 cpu 会在第一时间创建很多列表数据,这会导致一开始卡顿,创建完数据后,占用很大内存。但之后的刷新,不应该卡顿。

如果使用回收策略,内存压力小了,开始不需要进行大量的 cpu 计算,所以不会有开始渲染卡顿问题。但后面的快速刷新会消耗 cpu 。

3582 次点击
所在节点    程序员
29 条回复
LuckyLauncher
2024-07-24 10:18:09 +08:00
数据是数据,展示出来是“绘制”这个动作
你把你的手机屏幕上展示的东西想象成一张静态的图,你滑动的时候这张图是被实时绘制出来的,不管数据在哪,要渲染的组件有没有创建(哪怕是已经创建了但是给隐藏了),“绘制”这个动作是跑不了的

你可以用 canvas 之类的自己写一个列表看看
jones2000
2024-07-24 10:22:58 +08:00
虚拟表格不需要把所有数据都加载到内存, 只加载一个索引序号就可以了,滚到到哪里就请求哪一屏的数据。就算存在内存里面, 能用多少内存, 比起创建 10W 个 DOM 占用的内存,100W 条数据内存就小多了。
IvanLi127
2024-07-24 10:25:49 +08:00
CPU: 谢谢你
GPU: 我谢谢你
RightHand
2024-07-24 10:27:26 +08:00
单纯数据其实还好,绘制才是卡的大头。
weixind
2024-07-24 10:30:17 +08:00
这个场景的瓶颈首先是在渲染,而不是数据源。有定论的知识点,有啥可讨论的。
iOCZS
2024-07-24 10:32:01 +08:00
绘制的消耗是必然存在的,在绘制间隙的 CPU 时间片可以用于计算,这是合理的,CPU 闲着也是闲着。
不使用回收策略,那么 cpu 会在第一时间创建很多列表数据。这个有待商榷,一般是分页获取数据,因此内存消耗是累计的,CPU 未必存在一开始就卡的问题。
Kinnikuman
2024-07-24 10:32:51 +08:00
@LuckyLauncher

@RightHand

绘制是另一个问题了,有专门的硬件处理。

所以,我的问题有问题是吗?相对于绘制来讲,那些 cpu 计算复杂的列表如何更换数据,都是很 easy 的计算?
Kinnikuman
2024-07-24 10:35:19 +08:00
@iOCZS "CPU 闲着也是闲着",不这么认为,能让 cpu 少工作,也算是性能优化的一部分吧。当然这个话题中是舍弃掉内存来换取 cpu 的部分工作。而且这个讨论不考虑分页获取数据,就是一个几万几十万条的数据一次性加载到 list 中。
Chuckle
2024-07-24 10:36:19 +08:00
虚拟列表是在滚动时计算出要渲染的元素在数组中的索引范围,普通的定高、不定高的计算量不大,很流畅,但是不定高的瀑布流,还伴随着图片加载的话,计算量就很大了,写过个 demo ,https://list.qcqx.cn/#/list/virtualwaterfall
Chuckle
2024-07-24 10:38:16 +08:00
@Chuckle 后端把图片宽高返回的话,计算量能小点,小红书就是这么干的
ipwx
2024-07-24 10:52:35 +08:00
在桌面 UI 时代,有一个东西叫做 onDraw (clipRect):UI 框架告诉你,现在你这个控件需要显示 (x0,y0) -> (x1,y1) 区域的东西,你自己画吧。

所以你根本不需要构造一堆 DOM 元素。列表在你的内存里面仅仅是数据,比如 List[{name: Steven, age: 13, ...}],然后你自己先把每个列表项渲染出来的坐标范围给计算出来存着,然后根据 UI 的需求把显示出来的对象画出来就可以了。

而且如果你遍历一遍你的列表找 (x0,y0) -> (x1,y1) 范围内的元素慢(这是 O(n) 的操作),你可以上数据结构,比如线段树,然后你就 O(log n) 了。

用上这套优化,百万个元素也不在话下。毕竟内存里面放一百万个对象才多少,也就几百兆么(注意 1 兆 = 一百万字节)。
----

题外话,所以很多前端不理解 “干嘛老考数据结构和算法”,那是因为没遇上需求。。。
ipwx
2024-07-24 10:54:46 +08:00
另外吐槽一句,上古时代 onDraw 要写的东西太多了以至于是大神才能玩的。

后来各大 UI 框架都有了它们自己的绘图的框架,降低了这套东西的难度。我学得少,只知道一个 Qt 的 GraphicsView 干这事,还有 JS 可能有一些 Canvas 的库干这些活。其他就不知道了。
Chuckle
2024-07-24 11:04:08 +08:00
@Chuckle #9 拟列表一般都是滑到底部后增量加载,类似分页,并不是一次性把所有数据加进 list ,而且计算布局也限制在视口附近的元素,优化手段还是很多的,查找要渲染的元素范围用二分,当然,往下滑动多了,list 还是会很大,可以考虑分数组、按范围计算,甚至上 canvas ,不过一般来说那点数据量 cpu 应付得过来的,总比上万个 dom 元素好多了,至于内存占用,这个没特殊限制倒没大问题,100w 个对象也才多大,重点还是列表布局的渲染,数据量大了怎么搞都是妥协,布局还是得老老实实算。这 demo 写得也一般,但是不定高虚拟瀑布流也能应付无图片的上万条数据。
Skifary
2024-07-24 11:29:48 +08:00
"所以我觉得,如果不使用回收策略,那么 cpu 会在第一时间创建很多列表数据,这会导致一开始卡顿,创建完数据后,占用很大内存。但之后的刷新,不应该卡顿。

如果使用回收策略,内存压力小了,开始不需要进行大量的 cpu 计算,所以不会有开始渲染卡顿问题。但后面的快速刷新会消耗 cpu 。"

------------------------------------------------

1 ,你没有理解 UI 对象,任何框架的 UI 对象都有绘制函数,而绘制函数是每一帧都会执行的,不管 UI 对象是否处于可视范围内,这是大数据列表卡顿最根本的原因。

2 ,使用缓存只会创造固定数目的 UI 对象,那么无论多大的数据量,最终的需要绘制的对象永远只有那几个,不会随着数据量的增长而增长。

3 ,对比“后面的快速刷新会消耗 cpu”需要的 cpu 算力和“渲染成千上万 UI 对象”所需要的 cpu 算力相比就是九牛一毛。
crz
2024-07-24 13:09:09 +08:00
@Chuckle 不定高的问题是滚动条,普通元素的滚动条是和内容线性对应的,虚拟列表要手动对齐这部分交互体验。

以你的 demo 为例子,不定高度一页是 2000 条数据,ctrl+end 定位的话尾部应该是第 2000 条,我这里操作结果是 1946 。再一个是拖动滚动条,能明显看到鼠标指针和滚动条慢慢错位。

滚动条拉到一半位置,定高只要按索引折半,再细点就算上容器高度,简单的计算。不定高就不一样了。

碰到不定高度的直接想法就是算出来缓存,后台绘制,缓存。问题是虚拟列表数量往往不会少,就算只绘制一遍也是不小的开销,要是再加上加载图片的场景,时间和精确至少少一个。

后端给出高度也是一个方案,不考虑后端如何得到数据的问题,前端的一个问题场景是不定宽度的容器,数据高度受宽度影响也会变化。

不考虑滚动条的事行不行?也可以,虽然体验有区别,细节处大部分人没碰到也不会在意,也许以后大家都默认虚拟列表的交互就是这样的
kera0a
2024-07-24 13:17:35 +08:00
生成这么多元素,就算不绘制只去判断元素是否要绘制都是一笔很大的开销,列表每滚动一帧就得来一次批量判断,计算元素在不在显示范围
archxm
2024-07-24 13:35:46 +08:00
有优化手段的,做过 duilib
xu33
2024-07-24 15:23:59 +08:00
这个主要是渲染问题,一般数据全部放内存够了,数据如果实在大,可以考虑持久化存储再 load ,内存里只放一个 id
unco020511
2024-07-24 16:37:17 +08:00
你还是没理解
AV1
2024-07-24 18:02:27 +08:00
不是应该提供分页、跳页和条件筛选吗?
这么大量的数据,即使 UI 不卡,要找到想要的数据也不方便,用户体验也不会好。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1059633

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX