如何实现渲染几万条数据并且页面不卡顿?requestAnimationFrame
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何实现渲染几万条数据并且页面不卡顿?requestAnimationFrame相关的知识,希望对你有一定的参考价值。
参考技术A
链接:https://blog.csdn.net/m0_37631322/article/details/89678875
window.requestAnimationFrame API在动画方面有非常大的应用价值。
window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行;
注意:若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须 再次 调用window.requestAnimationFrame()
当你准备更新动画时你应该调用此方法。这将使浏览器在下一次重绘之前调用你传入给该方法的动画函数(即你的回调函数)。回调函数执行次数通常是 每秒60次 ,但在大多数遵循W3C建议的浏览器中,回调函数执行次数通常与浏览器屏幕刷新次数相匹配。为了提高性能和电池寿命,因此在大多数浏览器里,当requestAnimationFrame() 运行在后台标签页或者隐藏的<iframe> 里时,requestAnimationFrame() 会被暂停调用以提升性能和电池寿命。
回调函数会被传入DOMHighResTimeStamp参数,DOMHighResTimeStamp指示由RequestAnimationFrame()排队的回调开始触发的时间。指示当前被 requestAnimationFrame() 排序的回调函数被触发的时间。在同一个帧中的多个回调函数,它们每一个都会接受到一个相同的时间戳,即使在计算上一个回调函数的工作负载期间已经消耗了一些时间。该时间戳是一个十进制数,单位毫秒,最小精度为1ms(1000μs)。
性能优化:虚拟列表,如何渲染10万条数据的dom,页面同时不卡顿
最近做的一个需求,当列表大概有2万条数据,又不让做成分页,如果页面直接渲染2万条数据,在一些低配电脑上可能会照成页面卡死,基于这个需求,我们来手写一个虚拟列表
思路
- 列表中固定只显示少量的数据,比如60条
- 在列表滚动的时候不断的去插入删除dom
- startIndex、endIndex,不断的改变这个值来获取最新的显示列表
- paddingTop、paddingBottom撑开容器的滚动区域
首先看一下当直接插入2万条列表时,页面的性能
可以看到火焰图中已经有了红色的部分了,dom渲染也耗时也有1s多
再来看一下当使用虚拟列表时页面的性能
从火焰图中可以看出,火焰图中一篇绿油油的,这就证明,通过虚拟列表来进行渲染使页面性能得到了极大的提升
简单的虚拟列表demo实现
我们假设有一个容器,高度为600px,列表项每个高度为30px,那么根据列表的length我们就可以计算出滚动容器的总高度,也可以知道显示60条数据的高度,我们此时可以给容器加一个paddingBottom,来撑开容器,来模拟页面应该滚动的高度
this.paddingBottom = this.allHeight - this.scrollList.length * 30
容器同时还需要paddingTop用做当容器滚动顶部数据移除后撑起scrollTop
最后我们需要监听容器的滚动事件来不断的修改paddingTop、paddingBottom、startIndex、endIndex
最终效果
最后附上所有代码
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.container
width: 300px;
height: 600px;
overflow: auto;
border: 1px solid;
margin: 100px auto;
.item
height: 29px;
line-height: 30px;
border-bottom: 1px solid #aaa;
padding-left: 20px;
</style>
</head>
<body>
<div id="app">
<button @click="add">增加</button>
<div class="container" ref="container">
<div class="scroll-wrapper" :style="style">
<div v-for="(item, index) in scrollList" :key="index" class="item">item</div>
</div>
</div>
</div>
<script src="./vue.js"></script>
<script>
new Vue(
el: '#app',
data:
list: [
'测试数据'
],
startIndex: 0,
endIndex: 60,
paddingTop: 0,
paddingBottom: 0,
allHeight: 0
,
computed:
scrollList()
return this.list.slice(this.startIndex, this.endIndex)
,
style()
return
paddingTop: this.paddingTop + 'px',
paddingBottom: this.paddingBottom + 'px'
,
watch:
list(val)
const valLen = val.length
this.allHeight = valLen * 30
this.paddingBottom = this.allHeight - this.scrollList.length * 30
,
mounted()
const container = this.$refs.container
container.addEventListener('scroll', () =>
const top = container.scrollTop
this.startIndex = Math.floor(top / 30)
this.endIndex = this.startIndex + 60
this.paddingTop = top
if (this.endIndex >= this.list.length - 1)
this.paddingBottom = 0
return
this.paddingBottom = this.allHeight - 600 - top
)
,
methods:
add()
let arr = new Array(50000).fill(0)
arr = arr.map((item, index) =>
return index
)
this.list = [
...this.list,
...arr
]
)
</script>
</body>
</html>
以上是关于如何实现渲染几万条数据并且页面不卡顿?requestAnimationFrame的主要内容,如果未能解决你的问题,请参考以下文章
性能优化:虚拟列表,如何渲染10万条数据的dom,页面同时不卡顿