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