浏览器渲染机制
渲染流程
- 解析HTML标签,构建DOM树
- 解析CSS标签,构建CSSOM树
- 把DOM和CSS组合成渲染树(render tree)
- 在渲染树的基础上进行布局,计算每个节点的几何结构
- 把每个节点绘制到屏幕上(painting)
重绘(repaint)、回流(reflow)
- reflow
- 重新计算元素的几何尺寸
- repaint
- 绘制界面发生变化的部分
- 什么会触发重绘和回流
- 添加、删除、更新DOM节点(reflow、repaint)
- 修改元素的margin、padding、border(reflow、repaint)
- display:none(reflow,repaint)
- visibility:hidden(repaint)
- 修改颜色、背景色(repaint)
- 如何避免回流和重绘的建议
- 尽量一次性修改样式
- 给动画绝对定位和transform可以减小reflow
- DOM离线后修改
CSS与JS的加载
JS加载
- 遇到script标签,如果有src发请求获取JS,执行JS完毕后再解析后续标签
- JS的加载和执行会阻塞后续标签的解析
解释:所谓阻塞解析指的是影响DOM树的构建。因为JS里有个document.write可以再对应位置构建DOM。如果不等JS执行完就构建好了DOM树,那么document.write就没法在当前位置插入
- 页面中多个js存在会并行加载,只要js加载完后立马执行。但是如果某个js已经加载完成,但其前一个js还没有下载执行,那必须等到前一个js下载执行完后才能执行
- 建议把js放到body内部的末尾,以便让DOM尽快展现,同时方便js操作DOM
CSS加载
- 遇到link标签,会发请求获取CSS,同时不影响后续标签的解析
- css标签的加载不阻塞解析,但会阻塞渲染
- 解释:不阻塞解析指的是不影响DOM树的构建。阻塞渲染是因为CSS未加载完成导致CSSOM树未构建完成,从而无法构建渲染树,一直处于白屏状态(白屏指页面一片空白)
- 建议把CSS文件放在head标签里,今可能早的加载CSS
范例
问题:代码1和代码2白屏时间是几秒?最终可操作分别需要几秒
// 代码1
<!DOCTYPE html>
<html>
<head>
<script src="1s.js"></script>
<script src="10s.js"></script> // 此处进行DOM操作
</head>
<body>
<h1>hello</h1>
<link rel="stylesheet"href="1s.css">
<link rel="stylesheet"href="5s.css">
</body>
</html>
// 代码2
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet"href="1s.css">
<link rel="stylesheet"href="5s.css">
</head>
<body>
<h1>hello</h1>
<script src="1s.js"></script>
<script src="10s.js"></script> // 此处进行DOM操作
</body>
</html>
// tips: css和js文件是同时加载的,在网络里可以看到
async和defer
- 正常情况下JS加载会阻止DOM结构的解析,并且多个JS会按顺序依次执行
- < script async src="script1.js">
- async:加载和渲染后续文档元素的过程将和script.js的加载与执行并行进行(异步)
- < script defer src="script2.js">
- defer: 加载后续文档元素的过程将和script.js的加载并行进行(异步),但script.js的执行要在所有元素解析完成后执行
- 两者的差异
- async的存在不影响DOM的解析和其他资源的加载,特立独行,不保证顺序和时机
- defer存在不影响DOM的解析和其他资源的加载,但是会保证在DOM资源准备就绪后再执行,并且对于多个defer的外置js按顺序执行