浏览器的加载以及重绘和回流问题总结
浏览器的加载原则:按照自上而下的顺序加载,一般来说浏览器会依据html来创建DOM树,并通过CSS来共同生成Render树(去掉一些没用的东西)。而JS作为整体载入,需要等待DOM树创建完成,通常放在最后(window.onload)。详细一点的HTML加载流程如下:
1、输入网址浏览器向服务器发送请求获得html文件。
2、浏览器载入html代码,自上而下开始解析。
3、发现引入的CSS文件,加载这个CSS文件。
4、浏览器加载body中的元素,并结合CSS文件对页面进行渲染,
5、当浏览器遇到需要加载资源的标签时(img、video等),不会等待资源加载完成,而是继续向后渲染。
6、当资源加载完毕时,浏览器会重新渲染这部分。
7、浏览器遇到JS代码即加载,通常来说,如果script标签在某元素前面,标签中包含window.onload,则在Render树渲染完加载JS代码。
8、针对JS中对某些元素节点有特殊操作,则重新渲染这部分节点。
重绘(repaint)和回流(reflow)
重绘(repaint):当render树中一部分元素的属性(如一些外观、样式不影响布局的)发生变化时需要重新渲染的过程叫做重绘。
回流(reflow):当render树中一部分或者全部属性(如元素的规模、尺寸、隐藏等)发生改变而需要重建时叫做回流。
回流的发生:
1、DOM树的结构变化,如添加或删除元素。
2、元素的几何属性的改变(如margin、padding、width、height、border等)。
3、页面初始化渲染。
4、获取某些属性,浏览器为取得准确的值也会触发回流(offsetTop、clientTop、scrollTop、getComputedSyle()等等)。
5、浏览器窗口尺寸的改变。
* 浏览器减少回流重绘的方法: *
我们可以知道如果每句JS操作都去回流重绘,浏览器消耗巨大,所以通常浏览器会维护一个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量挥着到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样多次回流、重绘就变成一次。
* 我们日常开发时如何减少回流、重绘 *
减少回流、重绘其实就是需要减少对render tree的操作(合并多次多DOM和样式的修改),并减少对一些style信息的请求,尽量利用好浏览器的优化策略。具体方法有:
1、直接改变className,如果动态改变样式,则使用cssText(考虑没有优化的浏览器)
// 不好的写法
var left = 1;
var top = 1;
el.style.left = left + "px";
el.style.top = top + "px";
// 较好的写法
el.className += "className1";
// 比较好的写法
el.style.cssText += "left: " + left + "px; top: " + top + "px;";
2、让要操作的元素进行“离线处理”,处理完后一起更新
a). 使用DocumentFragment进行缓存操作,引发一次一次回流和重绘;
//不好的写法(模式中所说的反模式)
var p, t;
p = document.createElement('p');
t = document.createTextNode('fist paragraph');
p.appendChild(t);
document.body.appendChild(p); // 将引起一次回流
p = document.createElement('p');
t = document.createTextNode('second paragraph');
p.appendChild(t);
document.body.appendChild(p); // 将再引起一次回流
// 好的写法
var p, t, frag;
frag = document.createDocumentFragment();
p = document.createElement('p');
t = document.createTextNode('fist paragraph');
p.appendChild(t);
farg.appendChild(p);
p = document.createElement('p');
t = document.createTextNode('second paragraph');
p.appendChild(t);
farg.appendChild(p);
document.body.appendChild(frag); // 相比前面的方法,这里仅仅引起一次回流,倘若页面里有很多这样的操作,利用文档随便将会提升很多
b). 使用display: none技术,只引发两次回流和重绘;(只是减少重绘和回流的次数,display: none是会引起重绘和回流,相对而言,visibility: hidden只会引起重绘)
c). 使用cloneNode(true or false)和replaceChild技术,引发一次回流和重绘;
// 建立克隆镜像
var oldNode = document.getElementById('target'),
clone = oldNode.cloneNode(true);
// 处理克隆对象的操作...
//完成后
oldNode.parentNode.replaceChild(clone, oldNode);
3、不要经常访问会引起浏览器flush队列的属性,如果你确实要访问,利用缓存
// BAD WAY
for(循环){
el.style.left = el.offsetLeft + 5 + 'px';
el.style.top = el.offsetTop + 5 + 'px';
}
// 较好的写法
var left = el.offsetLeft,
top = el.offsetTop,
s = el.style;
for(循环){
left += 10;
top += 10;
s.left = left + "px";
s.top = top + "px";
}
4、让元素脱离动画流(position属性设为absolute或fixed,使元素脱离文档流),减少回流的Render Tree的规模。
5、尽量不使用表格布局,如果没有定宽表格一列的宽度由最宽的一列决定,那么可能在最后一行的宽度超出之前的列宽,引起整体回流造成table肯需要多次计算才能确定好其渲染树中节点的属性,通常需要花三倍同等元素的时间。
作者:rookie.he(kuke_kuke)
博客链接:http://blog.csdn.net/qq_33599109
欢迎关注支持,谢谢!
上一篇: 环境变量与全局变量
下一篇: node中的环境变量与全局变量