当我们遇到需要一次性向页面插入十万条数据的情况下,该如何保证页面不卡顿,维持一定的页面渲染性能
场景:
插入十万条数据,渲染到页面十万条数据
分析:
我们知道,UI渲染在浏览器渲染进程中属于宏任务
,且涉及到页面的绘制,因此执行完当前的的脚本,进入宏任务阶段后,同时由于数据量大,整个渲染耗费时间较长
方案:
- 把数据分批插入到页面✅(本篇内容)
- 虚拟列表,渲染应该渲染的
1. 分批每次插入20条(类似于手动给他分页加载)
//需要插入的容器
let ul = document.getElementById('container');
// 插入十万条数据
let total = 100000;
// 一次插入 20 条
let once = 20;
//总页数
let page = total/once
//每条记录的索引
let index = 0;
//循环加载数据
function loop(curTotal,curIndex){
if(curTotal <= 0){
return false;
}
//每页多少条
let pageCount = Math.min(curTotal , once);
setTimeout(()=>{
for(let i = 0; i < pageCount; i++){
let li = document.createElement('li');
li.innerText = curIndex + i + ' : ' + ~~(Math.random() * total)
ul.appendChild(li)
}
loop(curTotal - pageCount,curIndex + pageCount)
},0)
}
loop(total,index);
然而你会发现,当手速快一点时,会出现空白页、丢帧的情况;
这是为什么呢?
这里就跟浏览器的绘制频率有关系了,一般笔记本电脑的屏幕绘制频率
是60Hz,也就是每隔16.7ms(1000/60≈16.7)
计算机会绘制一次屏幕
在上述方案中,你的装载节点的时间点刚好在两次屏幕绘制之间,就会出现丢帧空白页面
引入requestAnimationFrame
因此,这里引入html5 提供的一个专门用于请求动画的 API:requestAnimationFrame
,“请求动画帧”,接收一个回调,系统在每次屏幕绘制之前,会处理这个回调函数
这样一来,就能够同步 装载节点 与 绘制屏幕 的频率了!
对上述代码稍作改动:
//循环加载数据
function loop(curTotal,curIndex){
if(curTotal <= 0){
return false;
}
//每页多少条
let pageCount = Math.min(curTotal , once);
//这里换成“请求数据帧”API
window.requestAnimationFrame(function(){
for(let i = 0; i < pageCount; i++){
let li = document.createElement('li');
li.innerText = curIndex + i + ' : ' + ~~(Math.random() * total)
ul.appendChild(li)
}
loop(curTotal - pageCount,curIndex + pageCount)
})
}
loop(total,index);
参考
优化大数据(时间分片)
requestAnimationFrame知多少