浏览器重绘与重排的性能优化
2018-01-17 16:30
381 查看
重绘与重排
当DOM变化影响了元素的几何属性(宽、高改变等等) 浏览器此时需要重新计算元素几何属性
并且页面中其他元素的几何属性可能会受影响
这样渲染树就发生了改变,也就是重新构造RenderTree渲染树
这个过程叫做重排(reflow)
如果DOM变化仅仅影响的了背景色等等非几何属性
此时就发生了重绘(repaint)而不是重排
因为布局没有发生改变
不管页面发生了重绘还是重排,它们都会影响性能(重绘还好一些)
能避免要尽量避免
触发重排
页面布局和元素几何属性的改变就会导致重排 下列情况会发生重排
页面初始渲染
添加/删除可见DOM元素
改变元素位置
改变元素尺寸(宽、高、内外边距、边框等)
改变元素内容(文本或图片等)
改变窗口尺寸
不同的条件下发生重排的范围及程度会不同
某些情况甚至会重排整个页面,比如滑动滚动条
浏览器的优化:渲染队列
举个小例子 比如我们想用js中修改一个div元素的样式
写下了以下代码
div.style.left = '10px'; div.style.top = '10px'; div.style.width = '20px'; div.style.height = '20px';1
2
3
4
我们修改了元素的left、top、width、height属性
满足我们发生重排的条件
理论上会发生4次重排
但是实际上只会发生1次重排
这是因为我们现代的浏览器都有渲染队列的机制
当我改变了元素的一个样式会导致浏览器发生重排或重绘时
它会进入一个渲染队列
然后浏览器继续往下看,如果下面还有样式修改
那么同样入队
直到下面没有样式修改
浏览器会按照渲染队列批量执行来优化重排过程,一并修改样式
这样就把本该4次的重排优化为1次
但是我们现在想要修改样式后在控制台打印
div.style.left = '10px'; console.log(div.offsetLeft); div.style.top = '10px'; console.log(div.offsetTop); div.style.width = '20px'; console.log(div.offsetWidth); div.style.height = '20px'; console.log(div.offsetHeight);1
2
3
4
5
6
7
8
千万不要写这样的代码,因为发生了4次重排
有同学可能不懂了,不是说浏览器有渲染队列优化机制吗?
为什么这样写就会发生4次重排
因为offsetLeft/Top/Width/Height非常叼
它们会强制刷新队列要求样式修改任务立刻执行
想一想其实这么做是有道理的
毕竟浏览器不确定在接下来的代码中你是否还会修改同样的样式
为了保证获得正确的值,它不得不立刻执行渲染队列触发重排(错的不是我,是这个世界)
以下属性或方法会刷新渲染队列
offsetTop、offsetLeft、offsetWidth、offsetHeight
clientTop、clientLeft、clientWidth、clientHeight
scrollTop、scrollLeft、scrollWidth、scrollHeight
getComputedStyle()(IE中currentStyle)
我们在修改样式过程中,要尽量避免使用上面的属性
重绘与重排的性能优化
分离读写操作
了解了原理我们就可以对上面的代码进行优化div.style.left = '10px'; div.style.top = '10px'; div.style.width = '20px'; div.style.height = '20px';1
console.log(div.offsetLeft);
console.log(div.offsetTop);
console.log(div.offsetWidth);
console.log(div.offsetHeight);
2
3
4
5
6
7
8
这样就仅仅发生1次重排了,原因相信大家已经很清晰了
把所有的读操作移到所有写操作之后
效率高多了
这是其中一种优化的方法
样式集中改变
还是我们最初修改样式的代码div.style.left = '10px'; div.style.top = '10px'; div.style.width = '20px'; div.style.height = '20px';1
2
3
4
虽然现代浏览器有渲染队列的优化机制
但是古董浏览器效率仍然底下,触发了4次重排
即便这样,我们仍然可以做出优化
我们需要cssText属性合并所有样式改变
div.style.cssText = 'left:10px;top:10px;width:20px;height:20px;';1
这样只需要修改DOM一次一并处理
仅仅触发了1次重排
而且只用了一行代码,看起来相对干净一些
不过有一点要注意,cssText会覆盖已有的行间样式
如果想保留原有行间样式,这样做
div.style.cssText += ';left:10px;';1
除了cssText以外,我们还可以通过修改class类名来进行样式修改
div.className = 'new-class';1
这种办法可维护性好,还可以帮助我们免除显示性代码
(有一点点性能影响,改变class需要检查级联样式,不过瑕不掩瑜)
缓存布局信息
我觉得缓存真是万金油,哪种性能优化都少不了它div.style.left = div.offsetLeft + 1 + 'px'; div.style.top = div.offsetTop + 1 + 'px';1
2
这种读操作完就执行写操作造成了2次重排
缓存可以进行优化
var curLeft = div.offsetLeft; var curTop = div.offsetTop; div.style.left = curLeft + 1 + 'px'; div.style.top = curTop + 1 + 'px';1
2
3
4
这也相当于是分离读写操作了
优化为1次重排
元素批量修改
现在我们想要向ul中循环添加大量li (如果ul还不存在,最好的办法是先循环添加li到ul,然后再把ul添加到文档,1次重排)
var ul = document.getElementById('demo'); for(var i = 0; i < 1e5; i++){ var li = document.createElement('li'); var text = document.createTextNode(i); li.appendChild(text); ul.appendChild(li); }1
2
3
4
5
6
7
我可以做出下面的优化
var ul = document.getElementById('demo'); ul.style.display = 'none'; <-- for(var i = 0; i < 1e5; i++){ var li = document.createElement('li'); var text = document.createTextNode(i); li.appendChild(text); ul.appendChild(li); } ul.style.display = 'block'; <--1
2
3
4
5
6
7
8
9
var ul = document.getElementById('demo'); var frg = document.createDocumentFragment(); <-- for(var i = 0; i < 1e5; i++){ var li = document.createElement('li'); var text = document.createTextNode(i); li.appendChild(text); frg.appendChild(li); <-- } ul.appendChild(frg); <--1
2
3
4
5
6
7
8
9
var ul = document.getElementById('demo'); var clone = ul.cloneNode(true); <-- for(var i = 0; i < 1e5; i++){ var li = document.createElement('li'); var text = document.createTextNode(i); li.appendChild(text); clone.appendChild(li); <-- } ul.parentNode.replaceChild(clone,ul); <--1
2
3
4
5
6
7
8
9
上面的方法减少重绘和重排的原理很简单
元素脱离文档
改变样式
元素回归文档
而改变元素就分别使用了隐藏元素、文档碎片和克隆元素
上面的方法我认为仅仅是理论上可以优化重排重绘次数
现代浏览器的优化可能会超过我们的想象
转载自:http://blog.csdn.net/q1056843325/article/details/53340308
相关文章推荐
- 优化CSS重排重绘与浏览器性能
- 网站性能优化 兼论浏览器的重绘与重排
- 优化CSS重排重绘与浏览器性能
- 浏览器重绘与重排的性能优化
- 浅谈DOM的操作以及性能优化问题-重绘重排
- 重绘与重排及它的性能优化
- 页面的重绘与重排原理以及性能优化
- reflow repaint 小心重绘与回流,优化浏览器性能
- 前端性能优化--为什么DOM操作慢? 浅谈DOM的操作以及性能优化问题-重绘重排 为什么要减少DOM操作 为什么要减少操作DOM
- 关于DOM的操作以及性能优化问题-重绘重排
- 浏览器的重绘与重排
- 160826、浏览器渲染页面过程描述,DOM编程技巧以及重排和重绘
- 浏览器重排和重绘
- 前端性能优化——桌面浏览器前端优化策略
- 浏览器渲染页面过程描述,DOM编程技巧以及重排和重绘
- web前端性能优化——DNS预解析和浏览器并发连接数
- 浏览器的加载与页面性能优化
- 浏览器渲染机制与性能优化
- ASP.NET性能优化之让浏览器缓存动态网页
- 前端性能优化 —— 移动端浏览器优化策略