一次加载1w条数据的最优解是什么?

2022-12-27 14:17:57 浏览数 (1)

首先先说结果,虚拟列表最优秀。

下面是一些测试和分析。

目标在那里,走着走着就到了 点赞再看,手留余香,与有荣焉

前奏:大列表的痛

最新版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

0 人点赞