有时候,咱们可能会在短时间外向页面中增加大量的节点,这样会让浏览器吃不消,导致浏览器卡顿甚至假死。
事实上,网页动画的每一帧(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设计模式与开发实际》
网页性能治理详解 作者:阮一峰