从web浏览器的渲染到性能优化

来源:互联网 发布:godaddy 获取域名证书 编辑:程序博客网 时间:2024/05/28 23:23

本文主要讲解web浏览器的渲染原理、流程到性能优化。主要有以下几点:

(1) script标签中的属性defer和async的区别

(2) 浏览器的渲染顺序

(3) 如何防止阻塞DOM渲染

(4) 如何保证首屏优化、关键渲染路径优化

(5) 如何从浏览器渲染、网络请求、js引擎机制优化性能


一: script标签中的属性defer和async的区别

要想让script标签中的defer和async属性生效,必须引入属性src,即js文件必须是外部引入的脚本文件。

下面讨论两个基本点:

 (1) 下载时是否会阻塞DOM的渲染

 (2) 执行时是否会阻塞DOM的渲染


首先谈一下async属性的特性:

(1) async属性是赋予脚本异步属性

(2) 页面一加载的时候,就立即下载脚本,不妨碍页面中的其他操作,比如下载其他资源、等待加载其他脚本

(3) js一旦下载好,就会立即执行

(4) 和文档同时呈现,标记为async的js脚本不会按照顺序执行

(5) 一般js不需要改变页面的DOM的时候,可以使用属性async进行异步加载

(6) 注意,异步脚本不要在加载期间修改DOM。有async属性的脚本,下载的时候不会阻塞DOM的解析,但是执行的时候会阻塞页面的解析

(7) 具有async属性的js脚本一定会在页面的load事件前执行,,但可能会在DOMContentLoaded事件触发之前或之后执行


其次谈一下defer属性的特性:

(1) defer属性赋予脚本延迟属性

(2)页面一加载的时候,就立即下载具有defer属性的js脚本,下载期间不阻塞DOM的解析,但等到整个DOM都解析完成之后才运行具有defer属性的JS脚本

(3) 下载的时候不阻塞DOM解析,执行具有defer属性的js时候也不会阻塞DOM的解析

(4) 具有defer属性的JS脚本会按照书写的前后顺序执行,因此脚本具有前后依赖关系可以放心使用(在实际中具有defer属性的脚本并不一定会按照书写顺序执行,所以最好是只让一个js脚本具有defer属性)

(5) 具有defer属性的js脚本会先于DOMContentLoaded事件执行(实际当中,也不一定会在DOMContentLoaded事件前执行)


现在总结一下async和defer属性的共同点:

(1) 两者在下载的时候都不会阻塞DOM解析

(2) 两者都只对外部脚本有效,如<script  src='index.js' defer='defer' ></script>或者<script  src='index.js'  async='async' ></script>

(3) 都可以使用onload事件进行一系列处理


现在总结一下async和defer属性的不同点:

(1) 不具有async和defer属性的js脚本,浏览器根据其所在位置阻塞解析,被下载紧接着执行,直到完成。

(2) 具有async属性的js脚本,在下载的时候不会阻塞DOM的解析。但是js文件一旦下载后之后,就会立即执行脚本,此时有可能会阻塞DOM的解析。即具有async属性的js脚本下载时候不会阻塞DOM的解析,但在执行的时候有可能会阻塞DOM的解析。

(3) 具有defer属性的js脚本,在下载的时候不会阻塞DOM的解析。js加载完之后,等待DOM渲染完成之后在执行js脚本,此时不会阻塞DOM的解析。即具有async属性的js脚本下载和执行的时候都不会阻塞DOM的解析。


两者的应用场景

(1) 具有async属性的js脚本,适合基本没有DOM操作、和模块的加载顺序无关、执行时间要短,否则对首屏还是有很大的影响的。

(2) 具有defer属性的js脚本,按序加载,加载和执行的时候都不会阻塞DOM的解析。


二:浏览器关键渲染顺序

接下来让我们来思考几个问题:

(1) 具有async属性的js脚本可能会阻塞DOM的解析,那么css在加载的时候回阻塞DOM的解析吗?

(2) 其他资源如何下载?

(3) 其他资源会阻塞DOM的解析吗?

(4)DOM parse是什么?

(5) 事件DOMContentLoaded和load分别是基于那个节点触发的?


首先让我们来看一下浏览器的渲染过程

下图展示了整个浏览器的渲染过程


(1) 文档对象模型(DOM)


上图展示了在浏览器里面,html的字节码被转换成DOM的过程

A、Bytes->Characters转换:根据字节Bytes的编码规则,将其转换为特定的字符Characters

B、Characters->Tokens(生成Tokens):将Characters转化为w3c定义的各种特定标签,生成Tokens(令牌)

C、Tokens->Nodes(词法解析):匹配字符串,将Tokens按照规则转换成节点对象(Nodes),其具有属性和规则

D、Nodes->DOM(DOM构建):根据每个节点的层次关系和属性,转换为直观的树形结构,具有明确的父子关系

至此,得到页面完整的DOM模型,以后的页面渲染(Render Tree)包括布局(Layout)和绘制(Paint)都是基于DOM的

注意:HTML都是增量构建的,在HTML文件还在传输的时候,HTML parse就已经开始了。


DOM代表页面的结构,决定整个初始化页面的布局;CSSOM决定页面的样式


(2) CSS对象模型(CSSOM)


    如上图所示是CSSOM构建流程图,将css文件的字节码转换为符合浏览器特定规则的字符,然后浏览器对其解析和构成树。整个计算的过程包括一套复杂的特异度计算规则(css属性来源->特异度大小->书写顺序前后覆盖),最终确定每个节点的样式值,形成CSSOM。 css被认为 是一种渲染阻塞资源(所谓的CSS白屏),因为渲染树是依赖CSSOM才能生成,然后才到浏览器的布局渲染流程,因此才将css放到head标签里面。


(3) 渲染树(Render Tree)

渲染树生成的大概过程如下:

A、从DOM的根节点开始遍历每个在HTML和CSS上的可见节点

B、对每个可见节点,为其找到适配的CSSOM并且组合他们

C、将每个节点(包括内容和样式)组建成Render Tree

所谓的可见节点:渲染树包含了渲染网页所需的所有节点,不需要渲染的节点是不会合并到渲染树里面的,比如元数据元素meta,base等,设置display:none的节点


(4) 布局(Layout)-计算渲染树节点大小

布局的最终效果是形成一个“盒子模型”,他需要精确地计算出每个元素所占据的位置坐标,将相对测量值(rem,vw,vh,em)转换成绝对像素。

下面讲解一下相对测量值的转换规则:

A、rem是相对根元素<html>的font-size值确定大小的;

B、vw,vh是相对视窗口的大小来确定的

我们可以在js里面改变节点的样式,但是css元素的位置和大小改变的,从而改变整体布局的话,那么浏览器会重新布局和渲染,这在开发过程中要注意避免和减小性能损耗的。


(5) 绘制(Paint)

根据background,border,box-shadow等样式和HTML内容,将Layout生成的区域填充为最终显示在屏幕上的像素

注意:DOMContentLoaded发生在DOM树构建完成之后发生的,也就是DOM解析完</html>的那一刻。load事件则是在所有资源都加载渲染之后才会触发


三、优化关键渲染路径

优化关键渲染路径是指优先显示与用户当前操作有关的内容。

1、CSS阻塞渲染






转载路径:http://blog.csdn.net/allenliu6/article/details/76609929