浏览器中键入网址再按下回车,发生了啥?
系统层
- 发起
http
请求,解析域名 DNS
- Chrome搜索自身
DNS
缓存。chrome输入chrome://net-internals/#dns可查看 - 搜索操作系统自身
DNS
缓存 - 读取本地
HOST
文件 - 以上都查询不到时,浏览器发送一个
DNS
的系统调用,DNS
请求到达宽带运营商服务器。 - 宽带运营商服务器查询自身缓存
- 没查询时,发起一个迭代(顶级域--次级域名--...)的
DNS
解析请求,直到获取到域名对应的IP
地址。
- Chrome搜索自身
拿到域名对应的
IP
并缓存- 宽带运营商服务器缓存
DNS
- 结果返回操作系统并缓存
DNS
- 结果返回浏览器并缓存
DNS
- 宽带运营商服务器缓存
获取到目标
IP
,发起Http
“三次握手”,建立起TCP/IP
连接- 客户端发送一个带有
SYN
标志的数据包给服务端 - 服务端回传一个带有
SYN/ACK
标志的数据包 - 客户端再回传一个带
ACK
标志的数据包给服务端
- 客户端发送一个带有
连接成功后,浏览器向服务器发起标准
Http
请求- 构建
Http
请求报文- 起始行(start line):描述请求或响应的基本信息;
- 请求行由三部分构成:请求方法:是一个动词,如
GET/POST
,表示对资源的操作; - 请求目标:通常是一个
URI
,标记了请求方法要操作的资源; - 版本号:表示报文使用的
HTTP
协议版本。 这三个部分通常使用空格(space)来分隔,最后要用CRLF
换行表示结束。
- 请求行由三部分构成:请求方法:是一个动词,如
- 头部字段集合(header):使用 key-value 形式更详细地说明报文;
- 允许客户端向服务器传递请求的附加信息
- 常见请求报头:
Content-Type, Cache-Control,CookieAccept-Encoding,Accept-Language
,等
- 消息正文(entity):实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据。
- 当使用
POST
,PUT
等方法时,通常需要客户端向服务器传递数据。
- 当使用
- 起始行(start line):描述请求或响应的基本信息;
- 过
TCP
协议,发送到服务器指定端口(Http
协议默认80
端口、Https
协议默认443
)
- 构建
服务器收到请求后,经过后端处理返回结果。(前后端分离)
- 响应报文
- 状态码
- 1xx:指示信息–表示请求已接收,继续处理。
- 2xx:成功–表示请求已被成功接收、理解、接受。
- 3xx:重定向–要完成请求必须进行更进一步的操作。
- 4xx:客户端错误–请求有语法错误或请求无法实现。
- 5xx:服务器端错误–服务器未能实现合法的请求。
- 响应报头
- 响应报文
- 状态码
- 响应报文
返回
Html
页面等资源,html
包含css/js
等资源,重复以上http
请求
渲染层
- Chrome浏览器的渲染引擎
Blink
(常说的浏览器内核)边接收边解析HTML
内容,浏览器自上而下逐行解析HTML
内容,经过词法分析、语法分析,构建DOM
树。HTML
文档被加载和解析完成时(DOM
树构建完成),触发DOMContentLoaded
事件,此时页面可以渲染展示出内容了。(html
引用的图片可能还在http
请求加载,当所有资源全部请求完成,触发load
事件)- 当遇到外部
CSS
链接时,不阻塞而继续构建 DOM 树。 - 当遇到外部
JS
链接时,异步获取资源(如果script
带有async
属性,将会继续DOM
的解析,当该资源加载完毕后,立即停止dom解析转而执行这个脚本,如果script
带有refer
属性,将会继续DOM
的解析,当该资源加载完毕后,继续等待dom
解析完毕)。JS
下载后,V8
引擎(常说的JavaScript引擎)会解析、编译JS
内容。由于 JS 可能会修改DOM
树和CSSOM
树而造成回流和重绘,故JS
会阻塞DOM
树的构建。
- 当遇到外部
- 下载
CSS
后,主线程会在合适时机解析CSS
内容,构建CSSOM
树。本来构建DOM
树和CSSOM树
是并行的,互不影响,但当解析到上文提到的JavaScript
时,需要构建完成CSSOM
树后,才能执行js
代码(DOM
树此时被挂起),因为js
可以查询/修改任意对象的样式,此时需要CSSOM
树构建完成。 - 浏览器结合
DOM
树和CSSOM
树构建Render
树。Render
树与DOM
树不同,渲染树中并没有head
、display
为none
等不必显示的节点。 - 浏览器渲染(布局 + 绘制 + 复合图层化),布局(Layout)环节主要负责各元素尺寸、位置的计算,绘制(Paint)环节则是绘制页面像素信息,合成(Composite)环节是多个复合层的合成,最终合成的页面被用户看到。
- 回流:DOM节点中的各个元素都是以盒模型的形式存在,这些都需要浏览器去计算其位置和大小等
- 重绘:当盒模型的位置,大小以及其他属性,如颜色,字体,等确定下来之后,浏览器便开始绘制内容
浏览器渲染流程总体解析

2b56a9509cdc11ebab90d9ae814b240d.png
结合上图,一个完整的渲染流程大致可总结为如下:
- 渲染进程将
HTML
内容转换为能够读懂的DOM
树结构。 - 渲染引擎将
CSS
样式表转化为浏览器可以理解的styleSheets
,计算出DOM
节点的样式。 - 创建布局树,并计算元素的布局信息。
- 对布局树进行分层,并生成分层树。
- 为每个图层生成绘制列表,并将其提交到合成线程。
- 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
- 合成线程发送绘制图块命令
DrawQuad
给浏览器进程。 - 浏览器进程根据
DrawQuad
消息生成页面,并显示到显示器上。
阻塞机制:
html
内容从上到下解析,浏览器遇到body
标签开始显示内容。CSS
不会阻塞DOM
的解析,JS
会阻止DOM
的解析。- 当文档加载过程中遇到
JS
文件,HTML
文档会挂起渲染过程,不仅要等到文档中JS
文件加载完毕还要等待解析执行完毕,才会继续HTML
的渲染过程。 - 现代浏览器都使用了预加载器,在
js
挂起DOM
解析时,会继续解析后面的html
,寻找需要下载的资源。预加载器下载这些资源,以减少JS
阻塞带来的影响。
优化方案
- 减少
http
请求数,如:雪碧图、合并CSS/JS
文件、缓存资源等(针对http1.1
) - 减少
http
请求资源体积,如:启用gzip
压缩、图片压缩、减少cookie
、按需加载等 css
放在head
中。由于同时具有DOM
和CSSOM
才能构建渲染树,所以HTML
和CSS
都是阻塞渲染的资源,所以尽量精简CSS
也是优化方式之一。js
放在body
底部,减少白屏时间。因为js
会阻止浏览器解析。- 减少回流和重绘制,比如不要一条一条修改
DOM
样式、使用documentFragment
操作DOM
等。