浏览器渲染原理及web前端分析,从浏览器渲染原理谈页面优化

浏览器渲染原理及web前端分析
浏览器的主要功能
用户界面:包括地址栏、后退/前进按钮、书签目录等,也就是除了用来显示你所请求页面的主窗口之外的其他部分。

浏览器引擎:用来查询及操作渲染引擎的接口。另外还用来操作浏览器的数据存储。

渲染引擎:用来显示请求的内容,例如,如果请求内容为html,它负责解析html及css,并将解析后的结果显示出来。

网络:用来完成网络调用,例如http请求,它具有平台无关的接口,可以在不同平台上工作。

UI后端:用来绘制类似组合选择框及对话框等基本组件,具有不特定于某个平台的通用接口,底层使用操作系统的用户接口。

JS解释器:用来解释执行JS代码。

数据存储:属于持久层,浏览器需要在硬盘中保存类似cookie的各种数据

图:浏览器主要组件图

浏览器渲染机制


我们现在要在浏览器中显示以上结构的HTML:

1.客户端浏览器开始从用户向服务器发出请求,服务器响应的将如上的HTML返回给请求的客户端浏览器中。

2.加载从标签开始,并发现标签内有个外部样式文件要加载

<link href="../css/css.css" rel="Stylesheet" type="text/css" />
1
3.这时客户端浏览器又向服务器发出一个请求加载css.css文件,服务器响应。

4.此时客户端浏览器继续加载html文件里里的标签,在css.css文件加载完后,同时开始渲染页面。

5.客户端浏览器在里的标签中发现一个标签并且引用了服务器进而的一张名为test.jpg的图片.客户端浏览器又向服务器发出一次请求。而浏览器不会因为此时正在加载标签里的图片而停止等待图片加载完,浏览器继续渲染还未完成的部分。

6.标签里的图片加载完了,则要显示出来,同时图片会占有一定的面积,又会影响到后面的布局,浏览器不得不又回来重新渲染一次这部分。

7.总算把body里的标签加载及渲染完后,浏览器又发现了一段代码:

<script type="text/javascript" src="js/js.js"></script>
1
8.浏览器又立刻向服务器发出请求加载js.js文件,服务器响应。

9.浏览器又在js.js文件中发现了一段代码是让

标签隐藏的代码,此时浏览器又要重新去渲染被隐藏的
部分。
10.最后到浏览器发现了为止。

参考资料: 
深入学习,偏底层(对于架构的理解更透彻) 
http://blog.csdn.net/findsafety/article/details/50424307

WEB前端分析测试点
12个测试要点

优点: 
纯粹的前端视角,可以测试任何的网站,不需要考虑后台

1.减少http请求的数量(把js,css合并),为了尽可能减少tcp链接的建立和释放连接的资源,减少读取资源读取IO的时间

2.用好浏览器缓存,浏览器会把所有的访问记录保存在硬盘中,下次访问时会判断时候已保存,提升访问速度。

3.利用gzip压缩机制,只针对文本类资源有效(js,css,html),文本的压缩比可以达到70%多。gif,png,等图片资源其实已经被压缩过了

4.把CSS文件放在html的开头,让浏览器一开始把渲染资源下载下来,保证以后的页面渲染比较流畅。 
css主要用来渲染,当发现有css会优先下载下来,便于渲染。

5.尽可能把js放在html的结尾,当页面渲染完成后,用户操作时候能达到动态的效果

6.尽量避免css表达式,判断浏览器的版本,分辨率等表达式

7.尽可能减少DNS查找,dns本身会消耗时间,尽可能使用相对路径。

DNS作用:把域名解析成IP地址

8.最好使用js压缩,比gzip更有针对性,js压缩并不是需要解压缩,而是压缩了以后js代码同样可以工作.

eg.var username–> var u; 
把长的字符变成短的字符,同样适用于css,html

9.尽量避免重定向redirect eg.访问www.baidu.com/ 
/本身也是一种重定向,我们网页内部尽可能制定到某一个指定的地址,以减少资源

10.去除重复的脚本,脚本重复太多会增大脚本的大小,消耗带宽资源 
如:加减法的函数,可以合并成一个操作函数

11.使用ajax请求,局部某些数据会变化,需要什么内容只请求那一部分内容 
提升用户体验,节省很多网络传输的带宽成本。 
目前,我们用jQuery js的框架写ajax非常方便.

12.使用CDN,内容分发网络。cdn不是从前端可控的技术,很大的缓存服务器 
减少总服务器的访问压力,提升用户的访问速度.
--------------------- 
作者:ElenaYu 
来源:CSDN 
原文:https://blog.csdn.net/yu1014745867/article/details/78518296?utm_source=copy 
版权声明:本文为博主原创文章,转载请附上博文链接!

一、关于浏览器渲染的容易误解点总结 
关于浏览器渲染机制已经是老生常谈,如果你想了解请点这里,而且网上现有资料中有非常多的优秀资料对此进行阐述。遗憾的是网上的资料良莠不齐,经常在不同的文档中对同一件事的描述出现了极大的差异。怀着严谨求学的态度经过大量资料的查阅和请教,将会在后文总结出一个完整的流程。在这里将会就一些我自己理解存疑的地方写出来 
1、DOM树的构建是文档加载完成开始的? 
DOM树的构建是从接受到文档开始的 一边会进行将字节转化为字符 字符转化为标记 标记构建dom树 
这个过程被分为标记化和树构建 
而这是一个渐进的过程。为达到更好的用户体验,呈现引擎会力求尽快将内容显示在屏幕上。它不必等到整个 HTML 文档解析完毕之后,就会开始构建呈现树和设置布局。在不断接收和处理来自网络的其余内容的同时,呈现引擎会将部分内容解析并显示出来。 
参考文档:http://taligarsiel.com/Projects/howbrowserswork1.htm 
2、渲染树是在DOM树和CSS样式树构建完毕才开始构建的吗? 
这三个过程在实际进行的时候又不是完全独立,而是会有交叉。会造成一边加载,一边解析,一边渲染的工作现象。 
参考文档:http://www.jianshu.com/p/2d522fc2a8f8 
3、css的标签嵌套越多,越容易定位到元素 
css的解析是自右至左逆向解析的,嵌套越多越增加浏览器的工作量,而不会越快。 
因为如果正向解析,例如「div div p em」,我们首先就要检查当前元素到 html 的整条路径,找到最上层的 div,再往下找,如果遇到不匹配就必须回到最上层那个 div,往下再去匹配选择器中的第一个 div,回溯若干次才能确定匹配与否,效率很低。 
逆向匹配则不同,如果当前的 DOM 元素是 div,而不是 selector 最后的 em,那只要一步就能排除。只有在匹配时,才会不断向上找父节点进行验证。 
打个比如 p span.showing 
你认为从一个p元素下面找到所有的span元素并判断是否有class showing快,还是找到所有的span元素判断是否有class showing并且包括一个p父元素快 
参考文档:http://www.imooc.com/code/4570

二、页面渲染的完整流程 
当浏览器拿到HTTP报文时呈现引擎将开始解析 HTML 文档,并将各标记逐个转化成“内容树”上的 DOM 节点。同时也会解析外部 CSS 文件以及样式元素中的样式数据。HTML 中这些带有视觉指令的样式信息将用于创建另一个树结构:呈现树。浏览器将根据呈现树进行布局绘制。 
  以上就是页面渲染的大致流程。那么浏览器从用户输入网址之后到底做了什么呢?以下将会进行一个完整的梳理。鉴于本文是前端向的所以梳理内容会有所偏重。而从输入到呈现可以分为两个部分:网络通信和页面渲染 
我们首先来看网络通信部分:

1、用户输入url并敲击回车。 
2、进行DNS解析。如果用户输入的是ip地址则直接进入第三条。但去记录毫无规律且冗长的ip地址显然不是易事,所以通常都是输入的域名,此时就会进行dns解析。所谓DNS(Domain Name System)指域名系统。因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析)。这个过程如下所示:

浏览器会首先搜索浏览器自身的DNS缓存(缓存时间比较短,大概只有2分钟左右,且只能容纳1000条缓存)。

如果浏览器自身缓存找不到则会查看系统的DNS缓存,如果找到且没有过期则停止搜索解析到此结束.
而如果本机没有找到DNS缓存,则浏览器会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器发起域名解析请求(通过的是UDP协议向DNS的53端口发起请求,这个请求是递归的请求,也就是运营商的DNS服务器必须得提供给我们该域名的IP地址),运营商的DNS服务器首先查找自身的缓存,找到对应的条目,且没有过期,则解析成功。
如果没有找到对应的条目,则有运营商的DNS代我们的浏览器发起迭代DNS解析请求,它首先是会找根域的DNS的IP地址(这个DNS服务器都内置13台根域的DNS的IP地址),找打根域的DNS地址,就会向其发起请求(请问www.xxxx.com这个域名的IP地址是多少啊?)
根域发现这是一个顶级域com域的一个域名,于是就告诉运营商的DNS我不知道这个域名的IP地址,但是我知道com域的IP地址,你去找它去,于是运营商的DNS就得到了com域的IP地址,又向com域的IP地址发起了请求(请问www.xxxx.com这个域名的IP地址是多少?),com域这台服务器告诉运营商的DNS我不知道www.xxxx.com这个域名的IP地址,但是我知道xxxx.com这个域的DNS地址,你去找它去,于是运营商的DNS又向linux178.com这个域名的DNS地址(这个一般就是由域名注册商提供的,像万网,新网等)发起请求(请问www.xxxx.com这个域名的IP地址是多少?),这个时候xxxx.com域的DNS服务器一查,诶,果真在我这里,于是就把找到的结果发送给运营商的DNS服务器,这个时候运营商的DNS服务器就拿到了www.xxxx.com这个域名对应的IP地址,并返回给Windows系统内核,内核又把结果返回给浏览器,终于浏览器拿到了www.xxxx.com对应的IP地址,这次dns解析圆满成功。

3、发起TCP的3次握手 
拿到域名对应的IP地址之后,User-Agent(一般是指浏览器)会以一个随机端口(1024< 端口 < 65535)向服务器的WEB程序(常用的有httpd,nginx等)80端口发起TCP的连接请求。这个连接请求(原始的http请求经过TCP/IP4层模型的层层封包)到达服务器端后(这中间通过各种路由设备,局域网内除外),进入到网卡,然后是进入到内核的TCP/IP协议栈(用于识别该连接请求,解封包,一层一层的剥开),还有可能要经过Netfilter防火墙(属于内核的模块)的过滤,最终到达WEB程序,最终建立了TCP/IP的连接。

4、建立TCP连接后发起http请求

5、服务器端响应http请求,浏览器得到html代码。以下为响应报文格式: 


以上是网络通信部分,接下来将会对页面渲染部分进行叙述。当浏览器拿到html后是如何进行页面渲染的
当浏览器拿到HTML文档时首先会进行HTML文档解析,构建DOM树。
遇到css样式如link标签或者style标签时开始解析css,构建样式树。HTML解析构建和CSS的解析是相互独立的并不会造成冲突,因此我们通常将css样式放在head中,让浏览器尽早解析css。
当html的解析遇到script标签会怎样呢?答案是停止DOM树的解析开始下载js。因为js是会阻塞html解析的,是阻塞资源。其原因在于js可能会改变html现有结构。例如有的节点是用js动态构建的,在这种情况下就会停止dom树的构建开始下载解析js。脚本在文档的何处插入,就在何处执行。当 HTML 解析器遇到一个 script 标记时,它会暂停构建 DOM,将控制权移交给 JavaScript 引擎;等 JavaScript 引擎运行完毕,浏览器会从中断的地方恢复 DOM 构建。而因此就会推迟页面首绘的时间。可以在首绘不需要js的情况下用async和defer实现异步加载。这样js就不会阻塞html的解析了。当HTML解析完成后,浏览器会将文档标注为交互状态,并开始解析那些处于“deferred”模式的脚本,也就是那些应在文档解析完成后才执行的脚本。然后,文档状态将设置为“完成”,一个“加载”事件将随之触发。注意,异步执行是指下载。执行js时仍然会阻塞。
在得到DOM树和样式树后就可以进行渲染树的构建了。应注意的是渲染树和 DOM 元素相对应的,但并非一一对应。比如非可视化的 DOM 元素不会插入呈现树中,例如“head”元素。如果元素的 display 属性值为“none”,那么也不会显示在呈现树中(但是 visibility 属性值为“hidden”的元素仍会显示) 

渲染树构建完毕后将会进行布局。布局使用流模型的Layout算法。所谓流模型,即是指Layout的过程只需进行一遍即可完成,后出现在流中的元素不会影响前出现在流中的元素,Layout过程只需从左至右从上至下一遍完成即可。但实际实现中,流模型会有例外。Layout是一个递归的过程,每个节点都负责自己及其子节点的Layout。Layout结果是相对父节点的坐标和尺寸。其过程可以简述为:

父节点确定自己的宽度
父节点完成子节点放置,确定其相对坐标
节点确定自己的宽度和高度
父节点根据所有的子节点高度计算自己的高度
1
2
3
4
此时renderTree已经构建完毕,不过浏览器渲染树引擎并不直接使用渲染树进行绘制,为了方便处理定位(裁剪),溢出滚动(页内滚动),CSS转换/不透明/动画/滤镜,蒙版或反射,Z (Z排序)等,浏览器需要生成另外一棵树 - 层树。因此绘制过程如下: 
获取 DOM 并将其分割为多个层(RenderLayer) 
将每个层栅格化,并独立的绘制进位图中 
将这些位图作为纹理上传至 GPU 
复合多个层来生成最终的屏幕图像(终极layer)。

三、HTML及CSS样式的解析 
HTML解析是一个将字节转化为字符,字符解析为标记,标记生成节点,节点构建树的过程。。CSS样式的解析则由于复杂的样式层叠而变得复杂。对此不同的渲染引擎在处理上有所差异,后文将会就这点进行详细讲解
1、HTML的解析分为标记化和树构建两个阶段 
标记化算法: 
是词法分析过程,将输入内容解析成多个标记。HTML标记包括起始标记、结束标记、属性名称和属性值。标记生成器识别标记,传递给树构造器,然后接受下一个字符以识别下一个标记;如此反复直到输入的结束。 
该算法的输出结果是 HTML 标记。该算法使用状态机来表示。每一个状态接收来自输入信息流的一个或多个字符,并根据这些字符更新下一个状态。当前的标记化状态和树结构状态会影响进入下一状态的决定。这意味着,即使接收的字符相同,对于下一个正确的状态也会产生不同的结果,具体取决于当前的状态。 
树构建算法 
在树构建阶段,以 Document 为根节点的 DOM 树也会不断进行修改,向其中添加各种元素。 
标记生成器发送的每个节点都会由树构建器进行处理。规范中定义了每个标记所对应的 DOM 元素,这些元素会在接收到相应的标记时创建。这些元素不仅会添加到 DOM 树中,还会添加到开放元素的堆栈中。此堆栈用于纠正嵌套错误和处理未关闭的标记。其算法也可以用状态机来描述。这些状态称为“插入模式”。

以下将会举一个例子来分析这两个阶段:

<html>
  <body>
    Hello world
  </body>
</html>

猜你喜欢

转载自blog.csdn.net/weixin_42400955/article/details/83051563
今日推荐