每日一句
I love you three thousand.
释义:我爱你三千遍。
简述浏览器的渲染过程
- 处理HTML标记构建DOM树
- 处理CSS标记构建CSSOM树
- 将DOM树和CSSOM树合成一个渲染树
- 根据渲染树进行布局,计算机每个节点在浏览器中的位置及大小
- 将每个节点都绘制到屏幕上
以上步聚并不一定按顺序执行,当DOM树,CSSOM树被css,js修改时,以上步聚会重复执行。
阻塞浏览器渲染
- CSS阻塞渲染
- 因为CSS被视为阻塞渲染的资源,所以浏览器在CSSOM构建完毕之前,不会渲染任何已处理的内容。
- CSSOM 构建时,JavaScript执行将暂停,直到CSSOM 就绪。
- CSS 不会阻塞HTML的解析,但是会阻塞渲染树的构建 所以我们需要将它尽早、尽快地下载到客户端,以便缩短首次渲染的时间。 也就是说,我们要把引入css的标签放在head标签内。
- JS阻塞渲染
- JS不加任何修饰时,默认会阻塞DOM解析和渲染。
- JavaScript 既可以读取和修改 DOM 属性,又可以读取和修改 CSSOM 属性。 所以,script 标签的位置很重要,在实际应用中我们通常把script标签放在body底部。
性能优化方案
1.script上加属性async,defer
对于js阻塞渲染我们可以加一些属性,改变阻塞模式
defer: 延迟执行 相当于告诉浏览器立即下载,但延迟执行。
<script src="xxx.js" defer></script>
async: 异步执行 告诉浏览器立即下载文件,与
defer不同的是,标记为async的脚本并不保证按照它们的先后顺序执行。
<script src="xxx.js" async></script>
蓝色线代表网络读取,红色线代表执行时间,这俩都是针对脚本的;绿色线代表 HTML 解析。
也就是说async是乱序的,而defer是顺序执行,这也就决定了async比较适用于百度分析或者谷歌分析这类不依赖其他脚本的库。
从图中可以看到一个普通的<script>标签的加载和解析都是同步的,会阻塞DOM的渲染,这也就是我们经常会把<script>写在<body>底部的原因之一,为了防止加载资源而导致的长时间的白屏,另一个原因是js可能会进行DOM操作,所以要在DOM全部渲染完后再执行。
注意: defer、async 对 inline-script 无效
2.css
<link>标签,浏览器就需要向服务器发出请求获得CSS文件,然后才继续构建DOM树和CSSOM树,可以合并所有CSS成一个文件,减少HTTP请求,减少关键资源往返加载的时间,优化渲染速度。
3.页面回流与重绘出发
回流必将引起重绘,重绘不一定会引起回流。
回流比重绘的代价要更高。所以要尽可能的避免
- CSS
1.避免使用 table 布局。
2.尽可能在 DOM 树的最末端改变 class。
3.避免设置多层内联样式。
4.将动画效果应用到 position 属性为 absolute 或 fixed 的元素上。
5.避免使用 CSS 表达式(例如:calc())。
- Javascript
1.避免频繁操作样式,最好一次性重写 style 属性,或者将样式列表定义为 class 并一次性更改 class 属性。
2.避免频繁操作 DOM,创建一个 documentFragment,在它上面应用所有 DOM 操作,最后再把它添加到文档中。
3.也可以先为元素设置 display: none,操作结束后再把它显示出来。因为在 display 属性为 none 的元素上进行的 DOM 操作不会引发回流和重绘。
4.避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
5.对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
4.其他优化方案
-
加载部分HTML
浏览器先加载主要HTML初始化静态部分,动态变化的HTML内容通过Ajax请求加载。这样可以减少浏览器构建DOM树的工作量,让用户感觉页面加载速度很快。 -
压缩
对HTML、CSS、JavaScript这些文件去除冗余字符(例如不必要的注释、空格符和换行符等),再进行压缩,减小文件数据大小,加快浏览器解析文件编码。 -
图片加载优化
1)小图标合并成雪碧图,进而减少img的HTTP请求次数;
2)图片加载较多时,采用懒加载的方案,用户滚动页面可视区时再加载渲染图片。 -
HTTP缓存
浏览器自带了HTTP缓存的功能,只需要确保每个服务器响应的头部都包含了以下的属性:
1)ETag: ETag是一个传递验证令牌,它对资源的更新进行检查,如果资源未发生变化时不会传送任何数据。当浏览器发送一个请求时,会把ETag一起发送到服务器,服务器会根据当前资源核对令牌(ETag通常是对内容进行Hash后得出的一个指纹),如果资源未发生变化,服务器将返回304 Not Modified响应,这时浏览器不必再次下载资源,而是继续复用缓存。
2)Cache-Control: Cache-Control定义了缓存的策略,它规定在什么条件下可以缓存响应以及可以缓存多久。
a、no-cache: no-cache表示必须先与服务器确认返回的响应是否发生了变化,然后才能使用该响应来满足后续对同一网址的请求(每次都会根据ETag对服务器发送请求来确认变化,如果未发生变化,浏览器不会下载资源)。no-store直接禁止浏览器以及所有中间缓存存储任何版本的返回响应。简单的说,该策略会禁止任何缓存,每次发送请求时,都会完整地下载服务器的响应。
b、public&private: 如果响应被标记为public,则即使它有关联的HTTP身份验证,甚至响应状态代码通常无法缓存,浏览器也可以缓存响应。如果响应被标记为private,那么这个响应通常只为单个用户缓存,因此不允许任何中间缓存(CDN)对其进行缓存,private一般用在缓存用户私人信息页面。
c、max-age: max-age定义了从请求时间开始,缓存的最长时间,单位为秒。 -
HTML文档结构层次尽量少,最好不深于六层;
-
样式结构层次尽量简单;
-
少量首屏样式内联放在标签内;
-
隐藏在屏幕外,或在页面滚动时,尽量停止动画;
-
尽量缓存DOM查找,查找器尽量简洁;
-
涉及多域名的网站,可以开启域名预解析。