arco-design-vue
arco-design-vue copied to clipboard
修正一处VList的性能优化
- [ ] I'm sure this does not appear in the issue list of the repository
Basic Info
- Package Name And Version: @arco-design/[email protected]
- Browser: chrome105.0.0.0
- Reproduction Link: https://github.com/arco-design/arco-design-vue/blob/main/packages/web-vue/components/_components/virtual-list-v2/virtual-list-item.tsx
问题virtual-list-item.tsx中的setItemSize()导致性能问题
在做一个下载列表,需要频繁的刷新列表中的下载进度,此时发现了一点性能问题,跟踪调试后发现是setItemSize方法的逻辑问题
#virtual-list-item.tsx
setup(props, { slots }) {
const key = getCurrentInstance()?.vnode.key as string | number;
const itemRef = ref<HTMLElement | ComponentPublicInstance>();
const setItemSize = () => {
// @ts-ignore
const ele = itemRef.value?.$el ?? (itemRef.value as HTMLElement);
if (!props.hasItemSize(key) && ele?.offsetHeight) {
props.setItemSize(key, ele.offsetHeight);
}
};
onMounted(() => setItemSize());
return () => {
const child = getFirstComponent(slots.default?.());
if (child) {
return cloneVNode(
child,
{
ref: itemRef,
},
true
);
}
return null;
};
},
#use-size.ts
const hasItemSize = (key: string | number) => {
return sizeMap.has(key);
};
当前逻辑是, 1.读取ele 2.读取key 3.hasItemSize --> 从useSize.sizeMap中读取height 4.如果读不到就读取ele的offsetHeight并保存到useSize.sizeMap中
但是,问题出在对固定高度的virtual-list-item,并没有优化
当List被设置为fixedSize=true estimatedSize=50 时,我们应该理解为 virtual-list-item 是固定的50的高度
对固定高度时(fixedSize),virtual-list-item.tsx可以进行优化
#use-size.ts
const hasItemSize = (key: string | number) => {
if (isFixed.value) return true //增加此处 固定高度时直接返回true,减少当大量数据时的map查找计算
return sizeMap.has(key);
};
#virtual-list-item.tsx
setup(props, { slots }) {
const itemRef = ref<HTMLElement | ComponentPublicInstance>();
const setItemSize = () => {
// @ts-ignore
if (!props.hasItemSize(key)){ //增加此行 使得固定高度时不需要运行下面的代码
const ele = itemRef.value?.$el ?? (itemRef.value as HTMLElement); //移动此行 固定高度时不需要读取ele
const key = getCurrentInstance()?.vnode.key as string | number; //移动此行 固定高度时不需要读取key
if ( ele?.offsetHeight) {//修改此行
props.setItemSize(key, ele.offsetHeight);//注:固定高度时也不需要保存ItemSize,减少大量数据时map的插入hash计算
}
}
};
onMounted(() => setItemSize());
return () => {
const child = getFirstComponent(slots.default?.());
if (child) {
return cloneVNode(
child,
{
ref: itemRef,
},
true
);
}
return null;
};
},
如上修改,为的是固定高度模式下,减少不必要的 1.读取ele 2.读取key 3.hasItemSize --> 从useSize.sizeMap中读取height 4.如果读不到就读取ele的offsetHeight并保存到useSize.sizeMap中
附性能截图,1000行数据需要 27 毫秒,不理想

@xiaosongmao123 目前在优化虚拟列表的性能问题,会在近期的版本中放出