浏览器的渲染流程、重绘(repaint)和重排(reflow)
浏览器的渲染流程
现在我们有如下一个网页,我们将根据如下网页对渲染流程进行解析
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Demo</title>
<link rel="stylesheet" href="./css/index.css">
</head>
<body>
<h1>Hello World!</h1>
<img src="http://www.baidu.com/baidu.png" alt="这是一个不存在的图片地址,图片不会被加载出来" />
<script src="./js/index.js"></script>
<p>Lorem</p>
</body>
</html>
对照网页的大致流程
细致的流程下面的流程图进行了更细致的呈现
这里称解析HTML的线程为主线程
根据上面的流程可以观察出CSS和JS会阻断主进程,根据这个渲染流程我们选择把CSS放在页面的最前面,让浏览器先加载并解析,这样做的好处是只要网页结构被解析出来,用户看到的就是有样式的漂亮的界面,避免给用户看到丑陋的网页,如果把CSS写在网页最后面的话,如果用户网络不好,会先看到丑陋的网页然后等CSS完成解析后才能看到漂亮的界面,这样会让用户的体验下降。而JS需要等页面加载完成后才可以进行交互,所以需要写在网页的最后面。一些我们引用的第三方JS公共库应该写在我们自己的JS代码前。
当DOM树加载完成会触发 DOMContentLoaded
document.addEventListener("DOMContentLoaded", function() {
console.log("DOM树已全部生成完毕");
});
当页面中的DOM以及所有的外部资源全部加载完毕后会触发 load 事件
window.onload = function () {
console.log("所有资源已加载完成");
}
load 事件不仅可以针对window,也可以为单个dom元素使用
document.querySelector('img').addEventListener('load', function () {
console.log("img 加载完成");
})
重排(reflow)
-
触发的场景
-
当直接或间接的修改元素的尺寸和位置时
并不是每次修改元素的尺寸和位置都会触发重排,因为重排非常耗时,需要重新构造整个网页,浏览器为了提升性能,当连续修改时,会把重排的时间延迟到连续的修改完成后进行,但是如果在连续的修改操作中获取了元素的尺寸则会立即进行重排
dom.style.width = '100px'; dom.style.height = '100px'; dom.style.position = 'absolute'; dom.style.left = '100px'; // 上面四句的连续修改并不会触发四次重排 // 而是在遇到下面这句获取dom尺寸信息的语句才会重排 var domWidth = dom.style.width; // 执行到上面这句时会触发重排,如果不进行重排的话 // 这里的width获取到的不是100px dom.style.top = '100px';
-
获取元素的尺寸和位置
获取元素的尺寸和位置时,浏览器会立即进行重排来确定最终的尺寸和位置信息从而进行准确的返回。
-
重绘(repaint)
重绘不会影响元素的排列,重绘不会导致重排,但重排一定会导致重绘。重绘的过程由GPU完成,并且不用重新构造一次页面,速度会比重排快很多,所以说仅会触发重绘的代码比会触发重排的代码高效很多
- 触发的场景
- 触发重排的时候一定触发重绘
- 改变元素的外观会触发重绘
- 字体颜色
- 圆角边框
- 背景图
- 等等