开发者社区> 佀无极> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

前端优化,了解浏览器重排与重绘

简介: 当DOM变化影响了元素的几何属性(宽、高改变等等)  浏览器此时需要重新计算元素几何属性  并且页面中其他元素的几何属性可能会受影响  这样渲染树就发生了改变,也就是重新构造RenderTree渲染树  这个过程叫做重排(reflow) 如果DOM变化仅仅影响的了背景色等等非几何属性  此时就发生.
+关注继续查看

2018年3月15日

当DOM变化影响了元素的几何属性(宽、高改变等等) 
浏览器此时需要重新计算元素几何属性 
并且页面中其他元素的几何属性可能会受影响 
这样渲染树就发生了改变,也就是重新构造RenderTree渲染树 
这个过程叫做重排(reflow)

如果DOM变化仅仅影响的了背景色等等非几何属性 
此时就发生了重绘(repaint)而不是重排 
因为布局没有发生改变

页面发生重绘和重排,都会影响性能(重绘还好一些),尽量避免或减少重排

 

触发重排

页面布局和元素几何属性的改变就会导致重排 
下列情况会发生重排

  • 页面初始渲染
  • 添加/删除可见DOM元素
  • 改变元素位置
  • 改变元素尺寸(宽、高、内外边距、边框等)
  • 改变元素内容(文本或图片等)
  • 改变窗口尺寸

不同的条件下发生重排的范围及程度会不同 
某些情况甚至会重排整个页面,比如滑动滚动条

浏览器的优化:渲染队列

  1.     div.style.left = '10px';
  2.     div.style.top = '10px';
  3.     div.style.width = '20px';
  4.     div.style.height = '20px';

如上,修改了元素的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);

如上,发生4次重排
offsetLeft/Top/Width/Height 会强制刷新队列要求样式修改任务立刻执行 
这么做是有道理的 
毕竟浏览器不确定在接下来的代码中你是否还会修改同样的样式 
为了保证获得正确的值,它不得不立刻执行渲染队列触发重排

以下属性或方法会刷新渲染队列

  • offsetTop、offsetLeft、offsetWidth、offsetHeight
  • clientTop、clientLeft、clientWidth、clientHeight
  • scrollTop、scrollLeft、scrollWidth、scrollHeight
  • getComputedStyle()(IE中currentStyle)

我们在修改样式过程中,要尽量避免使用上面的属性

重绘与重排的性能优化

分离读写操作

了解了原理我们就可以对上面的代码进行优化

  1. div.style.left = '10px';
  2. div.style.top = '10px';
  3. div.style.width = '20px';
  4. div.style.height = '20px';
  5. console.log(div.offsetLeft);
  6. console.log(div.offsetTop);
  7. console.log(div.offsetWidth);
  8. console.log(div.offsetHeight);

仅仅发生1次重排了,原因相信大家已经很清晰了 
把所有的读操作移到所有写操作之后 
 

样式集中改变

还是我们最初修改样式的代码

div.style.left = '10px';
div.style.top = '10px';
div.style.width = '20px';
div.style.height = '20px';

如上,虽然现代浏览器有渲染队列的优化机制
但是古董浏览器效率仍然低下,触发了4次重排 
即便这样,我们仍然可以做出优化 
我们需要cssText属性合并所有样式改变

    div.style.cssText = 'left:10px;top:10px;width:20px;height:20px;';
如上,只需要修改DOM一次一并处理 
仅仅触发了1次重排 
而且只用了一行代码,看起来相对干净一些

注意,cssText会覆盖已有的行间样式 
如果想保留原有行间样式,如下
    div.style.cssText += ';left:10px;';

除了cssText以外,我们还可以通过修改class类名来进行样式修改,如下
div.className = 'new-class';
这种办法可维护性好,还可以帮助我们免除显示性代码 
有很小的性能影响,改变class需要检查级联样式,但是符合BEM标准可以更好的解耦,增加可维护性,建议这样写
div.className = 'js-class';

缓存布局信息

我觉得缓存真是万金油,哪种性能优化都少不了它
    div.style.left = div.offsetLeft + 1 + 'px';
    div.style.top = div.offsetTop + 1 + 'px';
如上,这种读操作完就执行写操作造成了2次重排 
缓存可以进行优化

    var curLeft = div.offsetLeft;
    var curTop = div.offsetTop;
    div.style.left = curLeft + 1 + 'px';
    div.style.top = curTop + 1 + 'px';
如上,这也相当于是分离读写操作了 
优化为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);
}

我可以做出下面的优化
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';

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);

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);

上面的方法减少重绘和重排的原理很简单

  • 元素脱离文档
  • 改变样式
  • 元素回归文档

而改变元素就分别使用了
隐藏元素
文档碎片
克隆元素 

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Ngnix服务优化与防盗链(下)
Ngnix优化主要有两种,一种是配置上的优化,一种是内核上的优化。 本文将介绍Ngnix在配置方面的优化。 实验准备: 已安装好一台Nginx服务器,IP:172.16.10.101,域名:www.tt.com。
18 0
前端性能优化系列 | 加载优化(上)
1. 资源加载优先级 在浏览器发起网络请求时,并非每个字节都具有相同的优先级,所以,浏览器通常会对所要加载的内容进行推测,将相对重要的信息先呈现给用户。比如浏览器一般会先加载CSS,再去加载JavaScript脚本和图像文件。当然,浏览器的判断并不一定都是准确的,下面就来看看如何影响浏览器对资源加载的优先级。
100 0
Bootstrap响应式前端框架笔记三——代码与表格
Bootstrap响应式前端框架笔记三——代码与表格
43 0
Bootstrap响应式前端框架笔记八——按钮组
Bootstrap响应式前端框架笔记八——按钮组
91 0
+关注
佀无极
脚踏实地,心存高远!
文章
问答
文章排行榜
最热
最新
相关电子书
更多
基于浏览器的实时构建探索之路
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载