浏览器工作原理及前端优化学习

前面学了DOM,现在再看浏览器的渲染比较好理解。

浏览器工作原理

浏览器组件结构

1.用户界面,包括地址栏、前进/后退/刷新/停止/主页等按钮、书签菜单等。除了浏览器主窗口显示用户请求的页面外,其他显示的各个部分都属于用户界面。

2.浏览器引擎,处于用户界面和渲染引擎之间,负责在两者之间传递操作

3.渲染引擎,负责显示请求的内容,对于HTML,就负责解析 HTML 和 CSS 内容,并将解析后的内容显示在屏幕上。

4.网络,负责网络调用,如HTTP请求

5.JavaScript解释器,解析和执行JavaScript代码,比如chrome的javascript解释器是V8

6.用户界面后端,用于绘制基本的窗口小部件,比如下拉框和窗口

7.数据存储,这是数据持久层,浏览器需要将各种数据保存在本地硬盘,比如cookie

Chrome浏览器每个标签页都对应一个渲染引擎实例,每个标签页都是一个进程,一定程度上说明了Chrome浏览器比较占内存的原因

渲染引擎的工作流程

渲染引擎,我们一般也称为浏览器内核,可以说是浏览器最重要的一个模块。 Firefox使用基于Mozilla的Gecko,而Safari和Chrome使用的是Webkit。渲染引擎主要工作就是依据HTMl、XML、CSS等代码文档的描述,把页面显示出来。

流程示意图

Webkit:

image-20210414151428745

Gecko:

image-20210414151530114

两个渲染引擎虽然叫法不一样,但是整体流程基本差不多。

1.首先,渲染引擎通过网络组件获取请求的内容(HTML、CSS、JS代码等)

2.获取到内容后,渲染引擎会进行下列流程进行渲染工作

image

渲染过程

1.解析HTML生成DOM树

2.解析CSS生成CSSOM树

3.将DOM树和CSSOM树合并生成渲染树(Render Tree)

4.遍历渲染树开始布局,计算每个节点的位置大小信息。

5.绘制渲染树,渲染引擎会遍历渲染树,通过用户界面后端,将节点绘制出来。

构建DOM树

HTML 文档中的所有内容皆是节点,各节点之间拥有层级关系,如父子关系、兄弟关系等,彼此相连,构成DOM树。最常见的几种节点有:文档节点、元素节点、文本节点、属性节点、注释节点。

DOM节点树中节点与HTML文档中内容一一对应,DOM树构建过程:读取html文档,将字节转换成字符,确定tokens(标签),再将tokens转换成节点,以节点构建 DOM 树。

img

img

构建CSSOM树

CSS文档中,所有元素皆是节点,与HTML文件中的标签节点一一对应。CSS中各节点之间同样拥有层级关系,如父子关系、兄弟关系等,彼此相连,构成CSSOM树。

在构建DOM树的过程中,在 HTML 文档的 head 标签中遇到 link 标签,该标签引用了一个外部CSS样式表。由于预见到需要利用该CSS资源来渲染页面,浏览器会立即发出对该CSS资源的请求,并进行CSSDOM树的构建。

CSSOM树构建过程与DOM树构建流程一致:读取CSS文档,将字节转换成字符,确定tokens(标签),再将tokens转换成节点,以节点构建 CSSOM 树。

img

img

.CSS文件,又名层叠样式表。当CSSOM树生成节点时,每一个节点首先会继承其父节点的所有样式,层叠覆盖,然后再以”向下级联”的规则,为该节点应用更具体的样式,递归生成CSSOM树。譬如,上右图中第二层的p节点,有父节点body,因此该p将继承body节点的样式:”font-size: 16px;”。然后再应用该p节点自身的样式:”font-weight: bold;”。所以最终该p节点的样式为:”font-size: 16px;font-weight: bold;”。

渲染阻塞——加载JS

若在构建DOM树的过程中,当 HTML 解析器遇到一个 script 标记时,即遇到了js,将立即阻塞DOM树的构建,将控制权移交给 JavaScript 引擎,等到 JavaScript 引擎运行完毕,浏览器才会从中断的地方恢复DOM树的构建。
其根本原因在于,JS会对DOM节点进行操作,浏览器无法预测未来的DOM节点的具体内容,为了防止无效操作,节省资源,只能阻塞DOM树的构建。譬如,若不阻塞DOM树的构建,若JS删除了某个DOM节点A,那么浏览器为构建此节点A花费的资源就是无效的。

若在HTML头部加载JS文件,由于JS阻塞,会推迟页面的首绘。为了加快页面渲染,一般将JS文件放到HTML底部进行加载,或是对JS文件执行async或defer加载。

如果JavaScript脚本还操作了CSSOM,而正好这个CSSOM还没有下载和构建,浏览器甚至会延迟脚本执行和构建DOM,直至完成其CSSOM的下载和构建。

所以,script 标签的位置很重要。实际使用时,可以遵循下面两个原则:

CSS 优先:引入顺序上,CSS 资源先于 JavaScript 资源。
JS置后:我们通常把JS代码放到页面底部,且JavaScript 应尽量少影响 DOM 的构建。

当解析html的时候,会把新来的元素插入dom树里面,同时去查找css,然后把对应的样式规则应用到元素上,查找样式表是按照从右到左的顺序去匹配的。

例如: div p {font-size: 16px},会先寻找所有p标签并判断它的父标签是否为div之后才会决定要不要采用这个样式进行渲染)。
所以,我们平时写CSS时,尽量用id和class,千万不要过渡层叠。

构建渲染树

通过DOM树和CSS规则树我们便可以构建渲染树。浏览器会先从DOM树的根节点开始遍历每个可见节点。对每个可见节点,找到其适配的CSS样式规则并应用。

渲染树构建完成后,每个节点都是可见节点并且都含有其内容和对应规则的样式。这也是渲染树与DOM树的最大区别所在。渲染树是用于显示,那些不可见的元素当然就不会在这棵树中出现了,譬如。除此之外,display等于none的也不会被显示在这棵树里头,但是visibility等于hidden的元素是会显示在这棵树里头的。

渲染树(Render Tree)由DOM树、CSSOM树合并而成,但并不是必须等DOM树及CSSOM树加载完成后才开始合并构建渲染树。三者的构建并无先后条件,亦非完全独立,而是会有交叉,并行构建。因此会形成一边加载,一边解析,一边渲染的工作现象。

渲染树布局

布局阶段会从渲染树的根节点开始遍历,然后确定每个节点对象在页面上的确切大小与位置,布局阶段的输出是一个盒子模型,它会精确地捕获每个元素在屏幕内的确切位置与大小。

渲染树绘制

在绘制阶段,遍历渲染树,调用渲染器的paint()方法在屏幕上显示其内容。渲染树的绘制工作是由浏览器的UI后端组件完成的。

页面的重绘(repaint)和重排(reflow)

根据渲染树布局,计算CSS样式,即每个节点在页面中的大小和位置等几何信息。HTML默认是流式布局的,CSS和js会打破这种布局,改变DOM的外观样式以及大小和位置。这时就要提到两个重要概念:repaint和reflow。

replaint:屏幕的一部分重画,不影响整体布局,比如某个CSS的背景色变了,但元素的几何尺寸和位置不变。

reflow:也称回流,当渲染树节点发生改变,影响了节点的几何属性(如宽、高、内边距、外边距、或是float、position、display:none;等等),导致节点位置发生变化,此时触发浏览器重排(reflow),需要重新生成渲染树。譬如JS为某个p标签节点添加新的样式:”display:none;”。导致该p标签被隐藏起来,该p标签之后的所有节点位置都会发生改变。此时浏览器需要重新生成渲染树,重新布局,即重排(reflow)。

重排必将引起重绘,而重绘不一定会引起重排,并且我们应该减少和避免repaint和reflow。

前端性能优化

提高网页加载速度的必要性

总而言之就是增加用户体验好感

前端性能优化方案

减少DNS查找

DNS查找,即浏览器根据url中域名,查找该域名对应的服务器IP地址,然后才能根据服务器IP地址,下载到文件。

一般而言,电脑会进行DNS缓存,包括浏览器缓存、系统缓存、路由器缓存、ISP DNS缓存。所以,浏览器DNS查找顺序一般是这样的:浏览器缓存→系统缓存→路由器缓存→ISP DNS 缓存→递归搜索。

递归搜索,即ISP的DNS服务器从根域名开始进行递归查询,查找时间一般为20-120ms。

若没有DNS缓存,才会执行DNS递归搜索。但是显而易见,第一次访问网站首页时,是不会有DNS缓存的,必然会执行DNS查找。而每一个DNS查找,需要耗时20-120ms。因此,减少DNS查找能加快网页加载速度。

实例:将网站所需的文件下载到本地,而不是调用别人支持的CDN。

CSS优先加载,JS延迟加载

在解析HTML文件,构建DOM树时,一旦遇到link标记时,即遇到了CSS样式表,将之下载,便可立即构建渲染树,从而立即呈现页面效果。

而一旦遇到script 标记时,即遇到了JS脚本,将立即阻塞DOM树的构建,将控制权移交给 JavaScript 引擎,等到 JavaScript 引擎运行完毕,浏览器才会从中断的地方恢复渲染树的构建。

若将引入JS脚本的链接放到HTML页面顶部,那么在加载该页面时,一旦遇到JS,页面渲染就会停滞,出现一段时间的灰色空白,直到JS加载完成,才会出现页面内容,这对用户体验是不友好的。因此,我们需要将JS脚本放置到页面底部,或者让JS脚本异步或是延迟加载。

从严格意义上来说,CSS的优先加载及JS的延迟加载并不能从根本上提升网页加载速度,但是它们能使网页更快被渲染出来,使页面内容逐步呈现,增加用户等待的耐心,提升用户体验。

减少HTTP请求

HTTP请求,即客户端到服务器端的请求消息,包括资源请求、数据处理等。

  HTTP请求需从客户端发起请求,然后由服务器端进行数据处理,然后再返回数据或资源。一般而言,耗时据请求资源的大小,服务器网速,约数ms-数百ms之间。请求资源越大,所花费的时间越长,服务器网速越慢,所花费的时间也越长。

  一般而言,完成了DNS查找后,接下来便是进行HTTP请求,获取资源。首先下载HTML文件,然后解析HTML文件,根据HTML内容,获取CSS、JS及图片文件。每一个CSS链接、JS链接以及图片链接都是一个HTTP请求。

  每一个HTTP请求都需要花费额外的时间。因此,我们可以将一些可合并的资源进行合并,譬如将所有页面的css合并成一个style.css文件,譬如将所有页面的js合并成一个function.js文件,再譬如将一批小图标利用ps合成一张图片(此手段效果最显著,也最常用)。虽然有时文件会变大,但是在HTTP请求中,请求下载一个大小为100KB的资源文件,比请求下载两个大小为50KB的资源文件要快。

缩小文件

众所周知,HTTP请求中,返回的资源越大,HTTP请求所花费的时间越长,因此,缩小资源文件可以提升HTTP请求的速度,进而提升页面加载速度。不仅如此,还能节省服务器流量及空间。

一般而言,缩小文件主要是指图片压缩,也包括CSS、JS文件压缩,网上有成熟的代码在线压缩工具,譬如:在线JS/CSS/HTML 压缩

而图片压缩主要是指图片在不同的格式下、不同的分辨率下保存,其大小将会有巨大的差异。譬如同一张图片的png格式与jpg格式肉眼看起来几乎没有区别,但是其大小相差了约5倍。而jpg格式中级也比高级要小约莫1倍。当然,图片的不同格式有不同的用处,且分辨率越高,图片也越清晰。

因此,根据需求为图片选择合适的格式及分辨率,就能得到最小的图片文件。

具体操作:在ps中打开图片,同时按下ctrl+alt+shift+s,打开”存储为web所用格式”弹框,即可任意选择保存图片的格式及分辨率。

善用缓存

避免在HTML文件中使用style标签插入CSS样式,及使用script标签插入JS脚本。若在HTML文件中插入CSS及JS,那么它们无法进入缓存,每次刷新页面,都要重新加载,不但浪费了浏览器资源,拖慢了页面加载速度,而且显得冗余且复用性低,不利于日后的维护。因此,将CSS样式与JS脚本分离出来,形成CSS文件及JS文件,就能进入缓存,进而提高页面加载速度。

灵活使用cookie和localstorage。在使用接口时,灵活使用cookie和localstorage来缓存接口返回的信息,避免不必要的接口查询,从而提升页面加载速度。譬如:在登录页面登录时,缓存好用户信息,设置过期时间。在进入用户个人中心页面时,若数据并未过期,可以直接从缓存中取用户信息,不必再调起接口去获取用户信息。

代码优化

这块没仔细看,可以参考最后一篇文章

参考

https://moxiaoxi.info/2016/01/30/Browser/

https://juejin.cn/post/6844903565610188807

https://segmentfault.com/a/1190000017019877

https://www.cnblogs.com/chenyoumei/p/9156849.html

https://www.cnblogs.com/chenyoumei/p/9167238.html

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2020-2021 Blog of Tianze

请我喝杯咖啡吧~

支付宝
微信