有时候,咱们可能会在短时间外向页面中增加大量的节点,这样会让浏览器吃不消,导致浏览器卡顿甚至假死。
事实上,网页动画的每一帧(frame)都是一次从新渲染。每秒低于24帧的动画,人眼就能感触到进展。个别的网页动画,须要达到每秒30帧到60帧的频率,能力比拟晦涩。如果能达到每秒70帧甚至80帧,就会极其晦涩。大多数显示器的刷新频率是60Hz,为了与零碎统一,以及节俭电力,浏览器会主动依照这个频率,刷新动画(如果能够做到的话)。所以,如果网页动画可能做到每秒60帧,就会跟显示器同步刷新,达到最佳的视觉效果。这意味着,一秒之内进行60次从新渲染,每次从新渲染的工夫不能超过16.67毫秒。
以下代码演示一次性向页面中增加大量dom节点:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<style type="text/css">
#wrap {
display: flex;
flex-wrap: wrap;
width: 100%;
}
#wrap div {
margin: 10px 20px;
color: #f00;
}
</style>
</head>
<body>
<div id="wrap"></div>
</body>
</html>
export function timeTest1() {
const ary = []
const wrap = document.getElementById('wrap')
Array.from({length: 100000}).forEach((i, index) => ary.push(index))
// 创立dom节点并插入到id为wrap的元素中
const createEle = (text) => {
const div = document.createElement('div')
div.innerHTML = text
wrap.appendChild(div)
}
// 渲染函数
const renderList = function(ary, fn) {
// 记录开始工夫
const startTime = Date.now()
// 遍历数组,执行回调
ary.forEach(item => fn(item) )
// 记录完结工夫
const endTime = Date.now()
console.log('耗时 ', endTime - startTime)
}
// 执行渲染函数
renderList(ary, createEle)
}
这里一次性向网页中增加了10万个节点,耗时729毫秒,尽管不到1秒的工夫就渲染实现,然而在刚开始渲染的一瞬间页面会有显著卡顿景象。
应用分时函数:
export function timeTest2() {
const ary = []
const wrap = document.getElementById('wrap')
Array.from({length: 100000}).forEach((i, index) => ary.push(index))
// 创立dom节点并插入到id为wrap的元素中
const createEle = (text) => {
const div = document.createElement('div')
div.innerHTML = text
wrap.appendChild(div)
}
const renderList = timeChunk(ary, createEle, 15000, 16)
renderList()
}
/**
* 分时函数
* @param {Array} ary 遍历渲染的数组
* @param {Function} fn 数组每一项的回调函数
* @param {Number} count 一个工夫片段内遍历数组多少项
* @param {Number} time 工夫片段
* @returns {Function} 返回一个函数,造成闭包
*/
export const timeChunk = function(ary, fn, count, time = 100) {
let t = null
// 依据count将ary中的每一项顺次取出执行fn,直至ary长度为0
const start = function() {
for (var i = 0; i < Math.min(count || 1, ary.length); i++) {
const aryItem = ary.shift()
fn(aryItem)
}
}
// 造成一个闭包
return function() {
const timeStart = Date.now()
// time毫秒执行一下start函数,直至ary长度为0,革除定时器t
t = setInterval(function() {
if (ary.length === 0) {
const timeEnd = Date.now()
console.log('分时函数耗时 ', timeEnd - timeStart)
return clearInterval(t)
}
start()
}, time)
}
}
从后果来看,我设置每距离16毫秒向页面增加15000个节点,总共有100000个节点,共用时7612毫秒。渲染残缺个列表所需工夫的确比不应用分时函数长了很多,但页面相对而言也更晦涩一些。
分时函数的性能是能够将一个长列表的渲染分批执行,每批渲染多少个元素(count)和渲染每批所需的工夫(time)是能够通过参数传递的。这样做的益处是:咱们将一个大工作变成多个小工作,咱们能够管制多长时间外向页面增加多少个节点,从而达到不阻塞浏览器渲染的成果;这样做的毛病是:整个长列表渲染实现所需的工夫会更长。
内容参考:《JavaScript设计模式与开发实际》
网页性能治理详解 作者:阮一峰
发表回复