首先先说结果,虚拟列表最优秀。
下面是一些测试和分析。
目标在那里,走着走着就到了
点赞
再看,手留余香,与有荣焉
前奏:大列表的痛
最新版Chrome version:100.
- 一下子加载1w条总时间:382ms
- setTimeout分页(100条)加载1w条总时间:1965ms
- requestAnimationFrame分页(100条)加载1w条总时间:2156ms
测试代码如下:
代码语言:javascript复制/*
* @Author: pym
* @Date: 2022-04-27 12:07:41
* @LastEditors: pym
* @Description: TODO xxx
* @LastEditTime: 2022-04-27 13:31:34
*/
// import _ from 'lodash';
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
import './index.less';
// 利用babel来写jsx 运行的时候会转换成createElement创建
function Element() {
const [state, setState] = useState(false)
useEffect(() => {
const now = Date.now()
let ul = document.getElementById('container');
const total = 10000
let curNumer = 0
const key = 4
const pageCount = 100
switch (key) {
case 0:
// 一下子加载1w条总时间:382ms
for (let i = 0; i < total; i ) {
let li = document.createElement('li');
li.innerText = ~~(Math.random() * total)
ul.appendChild(li);
}
console.log('JS运行时间:', Date.now() - now);
setTimeout(() => {
console.log('总运行时间:', Date.now() - now);
}, 0)
break;
case 1:
// setTimeout分页(100条)加载1w条总时间:1965ms
function loop() {
if (curNumer < total) {
for (let i = 0; i < pageCount; i ) {
let li = document.createElement('li');
li.innerText = ~~(Math.random() * total)
ul.appendChild(li);
}
curNumer = curNumer pageCount
console.log('运行时间:', Date.now() - now, curNumer);
setTimeout(function () {
loop()
})
} else {
console.log('总运行时间:', Date.now() - now, curNumer);
}
}
loop()
break;
case 2:
// requestAnimationFrame分页(100条)加载1w条总时间:2156ms
function loop2() {
if (curNumer < total) {
for (let i = 0; i < pageCount; i ) {
let li = document.createElement('li');
li.innerText = ~~(Math.random() * total)
ul.appendChild(li);
}
curNumer = curNumer pageCount
console.log('运行时间:', Date.now() - now, curNumer);
window.requestAnimationFrame(() => loop2())
} else {
console.log('总运行时间:', Date.now() - now, curNumer);
}
}
loop2()
break;
case 4:
// 一下子使用DocumentFragment加载1w条总时间:382ms
const documentFrag = new DocumentFragment()
for (let i = 0; i < total; i ) {
let li = document.createElement('li');
li.innerText = ~~(Math.random() * total)
documentFrag.appendChild(li);
}
ul.appendChild(documentFrag)
console.log('JS运行时间:', Date.now() - now);
setTimeout(() => {
console.log('总运行时间:', Date.now() - now);
}, 0)
break;
default:
break;
}
// 将数据插入容器中
return function clean() {
console.log('clean')
}
}, [])
return <div className="container">
bigList
<div id='container'></div>
</div>
}
// 渲染dom元素 指定容器
ReactDOM.render(<Element />, document.getElementById('root'));
线上版本:代码片段
如果你需要首屏快的话,要用分页,其中requestAnimationFrame分页更为优秀,因为这个api会是系统调用的,刷新时机和屏幕刷新保持一致。setTimeout则不能保证一致。
至于加载总时间是一次性加载快,猜测是chrome做了优化。因为case 1的setTimeout是立即执行的和case 0 一下子全部加载应该是执行顺序一样的。但是case 0 更快,应该是Chrome做了对appendChild做了合并处理。为了测试是否因为chrome做了合并处理,我在case 4中使用了DocumentFragment
,结果发现和case 0 的表现一致。暂且,这样理解。
但是它们就算加载结束也会在快速滚动时候出现时候白屏。这时候只能使用
虚拟列表
解决。
救星:虚拟列表
「前端进阶」高性能渲染十万条数据(虚拟列表)
参考文章:
https://juejin.cn/post/6844903982742110216