js渲染10万数据列表,不阻塞UI

深渊向深渊呼唤

前言

最近公司项目快结项了,但是我发现公司的每个页面打开都比较卡,究其原因数据量大,请求多,渲染慢。加之面试的时候也遇到过此类问题,那么今天就来尝试去实现一下。

一、整理思路

首先我们要知道js处理大量数据并没有花费多长时间。耗时最长的是渲染dom元素。一次加载完需要耗费大量时间,所以我们可以把数据切割成一个个小块。每次渲染一小块就能够将dom渲染出来了。

二、代码实现

<ul></ul>
// 第一种实现方式
const $UL = document.querySelector('ul')
let size = 0
const myList = getList()

// 生成数据
function getList() {
    let list = []
    for (let i = 0; i < 5005000; i++) {
        list.push(i)
    }
    return list
}

function render(list) {
    let tempBox = document.createDocumentFragment()
    list.map(function (data) {
        let li = document.createElement('li')
        li.innerHTML = data
        tempBox.appendChild(li)
    })
    $UL.append(tempBox)
}

function splitList() {
    if (size + 100 < myList.length) {
        render(myList.slice(size, size + 100))
        size += 100
        requestAnimationFrame(splitList)
    } else {
        render(myList.slice(size, size + myList.length - size))
        size = myList.length - size
    }
}

requestAnimationFrame(splitList)

可能有些同学没用过[requestAnimationFrame],(https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame),建议先去了解一下,当然你也可以用计时器来代替,不写也是可以的。

三、优化代码

虽然上诉方式已经将渲染时间缩短了,但是我们想要的效果是,需要的时候再渲染这个元素,不需要/被隐藏的元素就不渲染。那么这该怎么实现呢,首先我们去监听进度条,根据进度条滚动的距离,渲染dom,那么上诉代码就会变成如下样子。

<ul ></ul>
const $UL = document.querySelector('ul')
let page_arg = {
    size: 0,
    count: 100,
}

const myList = getList()
$UL.onscroll = function () {
    if (this.scrollTop + this.clientHeight + 10 >= this.scrollHeight) {
        splitList()
    }
}

// 生成数据
function getList() {
    let list = []
    for (let i = 0; i < 10000000; i++) {
        list.push('我是数据'+i)
    }
    return list
}

function render(list) {
    let tempBox = document.createDocumentFragment()
    list.map(function (data) {
        let li = document.createElement('li')
        li.innerHTML = data
        tempBox.appendChild(li)
    })
    $UL.append(tempBox)
}

function splitList() {
    render(myList.slice(page_arg.size, page_arg.size + page_arg.count))
    page_arg.size += page_arg.count
}

splitList()

总结

写到这里渲染数据列表的问题就算是结束了,如果有什么地方写的不对,或者还能优化的地方还请各位大佬指出来,毕竟我也是第一次尝试渲染这么多数据,代码在这里,各位也可以自己去尝试一下。其实还可以在优化一下这个计算的时间,可以使用web Worker多开一个线程来协助计算,再次将js的计算时间压缩,不过对我来说已经足够了,对于追求性能的同学可以去尝试一下。然后分享一下自己的心得。嘿嘿,ok,这篇博客就到此为止了,谢谢各位的支持,有问题请私信我。

栏目