浏览器工作原理
前端岗位面试中,必问的一道题就是“从地址栏里输入URL到页面显示的过程发生了什么?”,在我看来这其实就是考察浏览器的工作原理,即从浏览器请求HTML内容到渲染页面的过程。
要回答这个问题,可以回答得很简单,也可以回答得很复杂。
简单回答:
- 根据输入的URL的域名解析拿到真实IP进行访问
- 访问真实IP从服务器请求数据
- 浏览器将请求回来的数据(HTML)进行解析
- 将HTML文档解析成DOM树、CSSOM树、合成渲染树
- 浏览器调用GPU将渲染树生成图像画面显示在屏幕上
其实上面的回答也能概括浏览器渲染页面的整个过程,但不够详细。下面我们来看下详细的渲染过程。
浏览器请求HTML内容到渲染页面的过程大体上可分为四个过程:
- 导航
- 获取/响应
- 解析
- 渲染
基本流程图如下
详细一点的图如下
接下来具体讲解下各个流程
导航
导航是加载web网页的第一个过程,从地址栏里输入URL就进入了导航流程,导航流程中所做的事情如下:
- 查找DNS
- TCP握手
- TLS协商
查找DNS
通常我们在浏览器里输入的是网站的域名,例如www.google.com,经DNS查询之后,得到一个对应该域名的IP地址,例如93.184.216.34
有了IP地址之后,接下来就是向目标服务器地址发起网络请求了。
TCP握手
有了IP地址之后,浏览器就向目标地址发起网络请求,通过TCP的三次握手建立连接,建立连接之后服务器就可以向浏览器响应数据了。
TLS协商
如今大部分站点都已升级HTTPS,HTTPS是基于TLS的安全版的HTTP,所以访问HTTPS的网站需要经过TLS的握手(协商)建立安全连接之后才能进行交换数据。
建立HTTPS安全连接比普通的HTTP连接需要花费更多的时间,但是这能保证数据的安全,这是值得的。
总结导航流程
导航流程就是在输入URL之后,根据域名去DNS系统查询对应的IP地址,根据得到的IP地址发起网络连接,经过TCP三次握手和TLS握手协商之后建立连接,服务器向浏览器响应数据的过程。下图展示了导航的基本流程
获取/响应
获取是通过HTTP发起网络请求获取资源
GET / HTTP/1.1
User-Agent: PostmanRuntime/7.28.4
Accept: */*
Postman-Token: 4cabe7f5-5deb-4259-a861-18305d4f3d34
Host: www.google.com
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
响应是HTTP请求之后,服务器响应的资源
HTTP/1.1 200 OK
Date: Wed, 22 Dec 2021 01:11:25 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Content-Encoding: gzip
Server: gws
Content-Length: 6780
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Set-Cookie: 1P_JAR=2021-12-22-01; expires=Fri, 21-Jan-2022 01:11:25 GMT; path=/; domain=.google.com; Secure
Set-Cookie: NID=511=XmMmhzsn4W85P7dvnvS5NnLI17nBbwIUpJz4Trnlxn8N7Eh9GSEEQoi1g4aeEZXjC6COePjj9_AX2lXbmTnoXKQlVsFHqSY5RyVgiTgz7fM4zQVXBZ1p7nwfAyjggjYa3UhlcixqfrZRb-BeNtg1YZwEkTWDE9Bib52JnpJw8Cc; expires=Thu, 23-Jun-2022 01:11:25 GMT; path=/; domain=.google.com; HttpOnly
Connection: close
响应的数据(HTML)在body里
<!doctype html>
<html itemscope="" itemtype="http://schema.org/WebPage" lang="ko">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
...
...
...
解析
经过HTTP请求服务器响应数据(HTML)之后就进入到HTML的解析阶段了。解析阶段的工作是将HTML解析成DOM树,将CSS解析成CSSOM树,然后将DOM树和CSSOM树合成渲染树。
解析HTML
浏览器通过HTML解析器解析HTML,先标记HTML并构建成DOM树,解析HTML是一个非常复杂的过程。这里简单描述一下解析过程。具体算法见解析算法
浏览器通过HTML解析器,将DOM元素和属性节点构造成树的结构
例如
<html>
<body>
<p>
Hello World
</p>
<div>
<img src="example.png"/>
</div>
</body>
</html>
以上HTML代码将解析为如下图所示的DOM树结构
解析CSS
浏览器通过CSS相关的解析器,将CSS解析成CSSOM树,CSS解析器会将CSS文件解析成StyleSheet对象,且每个对象都包含CSS规则,CSS规则对象包含选择器和声明对象,以及其他与CSS语法对应的对象。
例如,有以下CSS规则
p,div {
margin-top: 3px;
}
.error {
color: red;
}
CSS解析器将CSS规则解析成如下图的CSSOM树
预加载扫描器(preload scan)
浏览器构建DOM树时,整个过程是从上至下扫描解析的,如果这时有script链接了较大的js文件,这时需先下载完js文件,然后再回来继续解析,这个过程占用了主线程。
这种情况下,加入async和defer属性即可减少阻塞情况
- async,后台下载脚本,下载完则执行脚本,多个脚本加入async属性时下载完的脚本执行顺序无法确定,因为下载完脚本即执行。
- defer,将脚本延迟下载,等待HTML解析完再下在脚本
<link rel="stylesheet" src="styles.css"/>
<script src="myscript.js" async></script>
<img src="myimage.jpg" alt="image description"/>
<script src="anotherscript.js" defer></script>
构建渲染树
DOM树和CSSOM树构建完成之后,将这两棵树合成渲染树Renderer Tree。
构建渲染树过程中,浏览器大致执行以下操作
- 从DOM树的根节点开始遍历,遍历每个可见的节点
- 某些不可见的节点(例如,script、meta等),在渲染过程中将会被忽略
- 一些节点由于是使用CSS将其隐藏(例如:display: none)的也会被忽略
- 对于每个可见的节点,都会将应用上CSSOM对应的规则。
- Render树保存所有具有内容和计算样式的可见节点,根据CSS级联确定每个节点的计算样式。
最终输出一颗渲染树,这可渲染树包含屏幕上有所可见内容的内容和样式信息。渲染树构建完成之后,接下来进入“布局”阶段了。
渲染
渲染步骤包括样式、布局、绘制,在某些情况下还包括合成。
布局(重排)
布局是一个递归的过程,从根渲染器开始,计算每个节点的几何信息,确定渲染树中所有节点的宽度、高度和位置,以及确定每个页面上每个对象大小和位置。
第一次确定节点的大小和位置等几何信息成为布局,随后节点大小和位置发生变化需要重新计算的过程称为回流。
绘制
绘制是最后一个阶段,浏览器将布局阶段计算的几何信息转换为屏幕上的实际像素。绘制包括将元素的每个可视部分绘制到屏幕上,包括文本、颜色、边框、阴影和替换的元素(如按钮和图像)。
绘制过程有几个概念
- 重绘
- 合成
重绘
当元素的颜色等(除大小,位置)发生变化时,浏览器需要更新这些信息,这个过程称为重绘。
合成
在平滑滚动的场景下,浏览器经常需要计算样式,回流和重绘,这种情况下很多像素需要快速绘制,为了确保重绘的速度比初始绘制的速度更快,屏幕上的绘图通常被分解成数层。如果发生这种情况,则需要进行合成。
所有流程走完之后,用户就可以浏览页面了。
总结
- DNS 查找:查找 Web 地址的 IP。
- TCP 握手:为后续步骤设置客户端和服务器之间的 TCP/IP 通信。
- TLS 握手:保护将通过加密发送的信息。
- HTTP 通信:建立一种浏览器可以理解的通信方式。
- 浏览器解析:解析 HTML,生成DOM树、CSSOM树、合成渲染树。
- 浏览器渲染:经过布局、绘制后在浏览器窗口上渲染文档。
浏览器相关知识
浏览器主要组件
UI界面
包括地址栏、前进/后退按钮、书签、菜单等,其他各个显示的部分都属于用户界面
浏览器引擎
在用户界面和渲染引擎直接传送指令
渲染引擎
负责显示请求的内容,如果请求的内容是HTML,则解析HTML和CSS,并将解析后的内容显示在屏幕上。
网络
用于网络调用,比如HTTP请求。
用户界面后端
用于绘制基本的窗口小部件。
JavaScript解释器
用于解析和执行JavaScript代码
数据存储
持久层,是一个浏览器内的轻便的数据库,可以保存数据到硬盘。
Chrome浏览器架构
从图中可以看出, Chrome 浏览器包括:
- 1 个浏览器(Browser)主进程
- 1 个 GPU 进程
- 多个工具层进程
- 多个渲染进程
- 多个插件进程
- 多个扩展进程
浏览器进程
主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。
渲染进程
核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中,默认情况下,Chrome 会为每个 Tab 标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。
GPU 进程
Chrome 的 UI 界面选择采用 GPU 来绘制,这使得 GPU 成为浏览器普遍的需求。Chrome 在其多进程架构上也引入了 GPU 进程。
工具进程
工具进程用于短暂的工作;提供沙箱环境运行不信任的代码等
插件进程
主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响。
扩展进程
扩展程序对浏览器、页面和系统的访问受限;无需重启即可安装和卸载扩展程序
以上知识点为个人学习记录整理