大量数据的渲染优化-分页渲染方案
相信有一道耳熟能详的题目,如果前端获取到了 10w 条数据,应该怎么渲染?本文就以此为例,来进行切入,解析大量数据渲染的方案
直接渲染
-
样式代码比较简单,我就不做阐述了,展示一下直接渲染的js代码,如下:
const data = [] for (let i = 0; i < 100000; i++) { data.push({ id: i, name: `Item ${i}` }) } const box = document.querySelector('.box') const btn = document.querySelector('.btn') btn.addEventListener('click', function () { render(data) }) function render(list) { const htmlStr = list .map(item => { return `<div class="item"> <span>${item.id}</span> <span>${item.name}</span> </div>` }) .join('') box.innerHTML = htmlStr }
-
看一下结果:
-
从点击渲染开始,经过了一段较长的时间才渲染出来了dom,这还只是一些简单的dom结构,如果是一些复杂的dom的结构,那相信时间会更加的漫长,而实际上我们通常是不需要一次性直接看到全部的数据的,只需要满足最开始展示在容器范围内的数据即可,或者适当多出一些,所以我们不难想到,只要我分开渲染,每次渲染一部分,虽然总时间变长,但是从体验上来说,会好上很多
数据的拆分
-
现在我们拿到的数据是一个10w个数据的一维数组,但是如果我们需要每次渲染一部分的话,那这样的数据用起来可能就不是那么的舒服,所以我们可以转变一下思路,将其作为二维数组,[[1-10], [11-20]…]例如这样,就比较适合我们进行数据的操作了
-
处理结果如下:
-
可以看到,处理的时间还是非常短的,目前我所使用的机器配置还是比较低的,所以不用担心这些数据处理的损耗,如果是这一点都想省去一点的话,就可以每次获取一部分就渲染一部分,再次拿取下一部分在渲染,我这里为了方便,就直接处理了
使用定时器分页渲染
-
在完成这个之前,我们首先需要对 render 这个渲染函数进行改造,如下:
function render(list) { const fragment = document.createDocumentFragment() list.forEach(item => { const div = document.createElement('div') div.textContent = `${item.id}-${item.name}` div.classList.add('item') fragment.appendChild(div) }) box.appendChild(fragment) }
-
现在我们只需要一个函数,来帮助我们完成重复执行 render 函数即可,如下:
function exec() { // 边界判断 if (index >= renderList.length) return // 使用定时器主要是进入一个异步任务,不阻碍主线程的渲染 setTimeout(() => { render(renderList[index]) index++ // 再次调用 exec() }, 0) }
-
函数准备完毕之后,我们看一下整体的代码,如下:
const data = [] for (let i = 0; i < 100000; i++) { data.push({ id: i, name: `Item ${i}` }) } const renderList = [] // 处理数据 function cutChuck(list, size) { for (let i = 0; i < list.length; i += size) { renderList.push(list.slice(i, i + size)) } } cutChuck(data, 10) const box = document.querySelector('.box') const btn = document.querySelector('.btn') let index = 0 function exec() { if (index >= renderList.length) return setTimeout(() => { render(renderList[index]) index++ exec() }, 0) } btn.addEventListener('click', function () { exec() }) function render(list) { const fragment = document.createDocumentFragment() list.forEach(item => { const div = document.createElement('div') div.textContent = `${item.id}-${item.name}` div.classList.add('item') fragment.appendChild(div) }) box.appendChild(fragment) }
-
执行效果如图:
-
此时就可以看到,渲染就不会出现一开始那样的长时间的卡顿或白屏,而且滚动条还在自动往上滑动,就可以表示还在不停的渲染
-
当然如果你的案例觉得卡顿的话,可以去使用 requestAnimationFrame 来减少页面reflow的次数,提升性能,使用也是非常简单的,只是把通过 setTimeout 调用更换一下,具体的分析后续有时间会放在另一篇文章中
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!