6.1 KiB
title | date | author | tags | categories | ||
---|---|---|---|---|---|---|
浏览器的组成 | 2020-11-20 | ac |
|
|
浏览器加载网页时,会去加载和执行JavaScript脚本和CSS样式文件实现网页各种动态效果。
浏览器的组成
核心两大部分:渲染引擎和JavaScript解释器(JavaScript引擎),它们是互斥的不能同时运行。
JavaScript 引擎
主要作用是,读取网页中的 JavaScript 代码,对其处理后运行。 JavaScript 是一种解释型语言,也就是说,它不需要编译,由解释器实时运行。
- 优点:是运行和修改都比较方便,刷新页面就可以重新解释;
- 缺点:是每次运行都要调用解释器,系统开销较大,运行速度慢于编译型语言。
脚本的执行顺序由它们在页面中的出现顺序决定,这是为了保证脚本之间的依赖关系不受到破坏。
通常会将脚本文件都放在网页尾部加载,因为正常的网页加载流程:
- 浏览器一边下载 HTML 网页,一边开始解析。也就是说,不等到下载完,就开始解析。
- 解析过程中,浏览器发现
<script>
元素,就暂停解析,把网页渲染的控制权转交给 JavaScript 引擎。 - 如果
<script>
元素引用了外部脚本,就下载该脚本再执行,否则就直接执行代码。 - JavaScript 引擎执行完毕,控制权交还渲染引擎,恢复往下解析 HTML 网页。
浏览器一般有限制,同时最多下载6~20个资源,即最多同时打开的 TCP 连接有限制,这是为了防止对服务器造成太大压力。如果是来自不同域名的资源,就没有这个限制。所以,通常把静态文件放在不同的域名之下,以加快下载速度。
JS脚本的加载
浏览器加载JS脚本主要通过<script>
标签来加载和解析外部脚本或嵌入的JS代码。
<script>
标签可以添加一些属性来调节脚本的加载。
- defer属性:浏览器发现
<script>
标签有defer属性会继续往下解析HTML,同时并行下载脚本,等解析完HTML页面后,再执行下载好的JS代码 - async属性:浏览器发现
<script>
标签有defer属性会继续往下解析HTML,同时并行下载脚本,等到下载完后,如果HTML页面没有解析完会暂停,开始执行下载的脚本,等执行完再恢复解析HTML页面。
对于type属性是<script>
标签来指定脚本类型的,值为:text/javascript
(默认)或application/javascript
。如果是其它值,浏览器不会执行其中的代码。
渲染引擎
主要作用是,将网页代码渲染为用户视觉可以感知的平面文档。
不同的浏览器有不同的渲染引擎:
Firefox:Gecko
引擎Safari:WebKit
引擎Chrome:Blink
引擎IE: Trident
引擎Edge: EdgeHTML
引擎
渲染引擎处理网页,通常分成四个阶段(渲染机制):
- 解析代码:HTML 代码解析为 DOM,CSS 代码解析为 CSSOM(CSS Object Model)。
- 对象合成:将 DOM 和 CSSOM 合成一棵渲染树(render tree)。
- 布局:计算出渲染树的布局(layout),流式布局模型(Flow Based Layout)
- 绘制:将渲染树绘制到屏幕。
以上四步并非严格按顺序执行,往往第一步还没完成,第二步和第三步就已经开始了。所以,会看到这种情况:网页的 HTML 代码还没下载完,但浏览器已经显示出内容了。
有了 RenderTree
,就知道了所有节点的样式,然后计算它们在页面上的大小和位置,最后把节点绘制到页面上。
重流|重绘
渲染树转换为网页布局,称为“布局流”(flow);布局显示到页面的这个过程,称为“绘制”(paint)。它们都具有阻塞效应,并且会耗费很多时间和计算资源。
页面生成以后,脚本操作和样式表操作,都会触发“重流”(reflow)和“重绘”(repaint)。用户的互动也会触发重流和重绘,比如设置了鼠标悬停(a:hover
)效果、页面滚动、在输入框中输入文本、改变窗口大小等等。
重流和重绘并不一定一起发生,重流必然导致重绘,重绘不一定需要重流。比如改变元素颜色,只会导致重绘,而不会导致重流;改变元素的布局,则会导致重绘和重流
如何较少重绘和重流
- 使用 transform 替代 top
- 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回 流(改变了布局
- 避免使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局。
- 尽可能在 DOM 树的最末端改变 class,重流是不可避免的,但可以减少其影 响。尽可能在 DOM 树的最末端改变 class,可以限制了重流的范围,使其影响 尽可能少的节点。
- 避免设置多层内联样式,CSS 选择符从右往左匹配查找,避免节点层级过多。尽可能的避免写过于具体的 CSS 选择器,然后对于 HTML 来说也尽 量少的添加无意义标签,保证层级扁平。
- 将动画效果应用到 position 属性为 absolute 或 fixed 的元素上,避免影响其他元 素的布局,这样只是一个重绘,而不是重流。
浏览器优化
现代浏览器大多都是通过队列机制来批量更新布局,浏览器会把修改操作放在队列中,至少一个浏览器刷新(即 16.6ms)才会清空队列,但当你获取布局信息的时候,队列中可能有会影响这些属性或方法返回值的操作,即使没有,浏览器也会强制清空队列,触发回流与重绘来确保返回正确的值。
主要包括以下属性或方法:
- offsetTop、offsetLeft、offsetWidth、offsetHeight
- scrollTop、scrollLeft、scrollWidth、scrollHeight
- clientTop、clientLeft、clientWidth、clientHeight
- width、height
- getComputedStyle()
- getBoundingClientRect()
所以,我们应该避免频繁的使用上述的属性,他们都会强制渲染刷新队列。
参考文章
[1] 浏览器环境概述 https://wangdoc.com/javascript/bom/engine.html