16

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

 3 years ago
source link: https://blog.csdn.net/weixin_43889562/article/details/113128957
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

一、整理思路

首先我们要知道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 style="overflow: auto; height:400px;"></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,这篇博客就到此为止了,谢谢各位的支持,有问题请私信我。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK