细说网页加载小细节

85 阅读3分钟

浏览器渲染机制

渲染流程
  • 解析HTML标签,构建DOM树
  • 解析CSS标签,构建CSSOM树
  • 把DOM和CSS组合成渲染树(render tree)
  • 在渲染树的基础上进行布局,计算每个节点的几何结构
  • 把每个节点绘制到屏幕上(painting)
重绘(repaint)、回流(reflow)
  1. reflow
  • 重新计算元素的几何尺寸
  1. repaint
  • 绘制界面发生变化的部分
  1. 什么会触发重绘和回流
  • 添加、删除、更新DOM节点(reflow、repaint)
  • 修改元素的margin、padding、border(reflow、repaint)
  • display:none(reflow,repaint)
  • visibility:hidden(repaint)
  • 修改颜色、背景色(repaint)
  1. 如何避免回流和重绘的建议
  • 尽量一次性修改样式
  • 给动画绝对定位和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加载
  1. 遇到link标签,会发请求获取CSS,同时不影响后续标签的解析
  2. css标签的加载不阻塞解析,但会阻塞渲染
  • 解释:不阻塞解析指的是不影响DOM树的构建。阻塞渲染是因为CSS未加载完成导致CSSOM树未构建完成,从而无法构建渲染树,一直处于白屏状态(白屏指页面一片空白)
  1. 建议把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
  1. 正常情况下JS加载会阻止DOM结构的解析,并且多个JS会按顺序依次执行
  2. < script async src="script1.js">
  • async:加载和渲染后续文档元素的过程将和script.js的加载与执行并行进行(异步)
  1. < script defer src="script2.js">
  • defer: 加载后续文档元素的过程将和script.js的加载并行进行(异步),但script.js的执行要在所有元素解析完成后执行
  1. 两者的差异
  • async的存在不影响DOM的解析和其他资源的加载,特立独行,不保证顺序和时机
  • defer存在不影响DOM的解析和其他资源的加载,但是会保证在DOM资源准备就绪后再执行,并且对于多个defer的外置js按顺序执行