前端优化之渲染百万条数据不卡顿
·
方法如下:
Document.createDocumentFragment(): 用来创建虚拟DOM
window.requestAnimationFrame:告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。
在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<ul></ul>
<script>
// createDocumentFragment
// requestAnimationFrame
// 百万条数据
let total = 1000000;
// 单次插入 可自定义
let once = 20;
// 需要插入的次数 向上取整
let loopCount = Math.ceil(total / once);
// 当前渲染次数
let countRender = 0;
function render() {
// 需要插入的目标对象
const targetElement = document.querySelector("ul");
// 文档因为存在片段于内存中,并不在DOM树中,将所以子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段通常会带来更好的性能。
// 创建一个虚拟Dom节点 插入真实文档之前不会触发dom渲染、回流等操作
// 因此能够很大程度减少dom操作所带来的的性能损耗
const fragment = document.createDocumentFragment();
// 对虚拟节点插入dom节点,也不会触发真是dom操作,同上
for (let i = 0; i < 20; i++) {
// 搞个节点
const li = document.createElement("li");
// 给li搞点内容
li.innerHTML = Math.random();
// 插入到虚拟节点
fragment.appendChild(li);
}
// 插入到真实节点的时候,只会把虚拟fragment下的子孙节点插入
targetElement.appendChild(fragment);
// 渲染次数加1,控制递归的次数
countRender++;
// // 递归调用
if (countRender < loopCount) {
// window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。
// 回调函数执行次数通常是每秒60次,但在大多数遵循W3C建议的浏览器中,回调函数执行次数通常与浏览器屏幕刷新次数相匹配。
// 能够把每次dom的操作汇总在下一次重绘之前更新动画帧
// 因此在浏览器单线程的机制下,能够无卡顿的加载,百万级列表
window.requestAnimationFrame(render);
}
}
// 执行渲染
render();
</script>
</body>
</html>
还有一种方案可以提高性能:
如果对于大量的数据,只应用于展示的话,可以使用Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;(这样可以让Vue不对对象增加getter和setter操作,从而提高性能)
-
不能添加新属性
-
不能删除已有属性
-
不能修改已有属性的值
-
不能修改原型
-
不能修改已有属性的可枚举性、可配置性、可写性
var obj = {
name: '张三',
age: 18,
address: '上海市'
}
obj.__proto__.habit = '运动'
// 冻结对象
Object.freeze(obj)
// 不能添加新属性
obj.sex = '男'
console.log(obj) // {name: "张三", age: 18, address: "上海市"}
// 不能删除原有属性
delete obj.age
console.log(obj) // {name: "张三", age: 18, address: "上海市"}
// 不能修改已有属性的值
obj.name = '李四'
console.log(obj) // {name: "张三", age: 18, address: "上海市"}
// 不能修改原型
obj.__proto__ = '随便什么值'
console.log(obj.__proto__) // {habit: "运动", constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, …}
// 不能修改已有属性的可枚举性、可配置性、可写性
Object.defineProperty(obj,'address',{ // TypeError: Cannot redefine property: address
enumerable: false,
configurable: false,
writable: true
})
深冻结
var obj = {
name: '张三',
info: {
a: 1,
b: 2
}
}
function deepFreeze(obj) {
// 获取所有属性
var propNames = Object.getOwnPropertyNames(obj)
// 遍历
propNames.forEach(item => {
var prop = obj[item]
// 如果某个属性的属性值是对象,则递归调用
if (prop instanceof Object && prop !== null) {
deepFreeze(prop)
}
})
// 冻结自身
return Object.freeze(obj)
}
deepFreeze(obj)
obj.name = '李四'
console.log(obj) // {name: "张三", info: {…}}
obj.info.a = 100
console.log(obj.info) // {a: 1, b: 2}
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)