1. 输入阶段
- 输入第一个字符开始,浏览器会检索历史记录,显示匹配的地址(如果有的话)
- 输入完毕之后,浏览器会根据URL的规则判断输入的内容是搜索内容还是URL,如果是搜索内容,则回车之后通过默认的搜索引擎,拼接url跳转。如果是URL,则会加上协议(如果缺少的情况下),拼成完成的URL进行访问。
2. URL请求阶段
浏览器通过进程间的通信(IPC)把URL请求发送到网络进程,网络进程发起真正的URL请求。
发起请求前,网络进程根据请求的URL查询是否缓存了该资源。如果有,那么直接返回资源给浏览器进程;如果没有,会进程DNS解析。
首先查看浏览器是否对该域名有缓存,然后是hosts文件,如果都没有,则需要请求域名服务器进行查询。如果协议请求是HTTPS,还需要建立TLS连接。
接下来就是通过IP地址和服务器建立TCP连接(三次握手),连接之后,浏览器会构造请求行、请求头,向服务器发送构建的请求信息。
3. 服务端阶段
如果是静态网站,一般会经nginx做反向代理,根据请求的域名做location到服务器的某个静态文件上,比如:/root/www/index.html;
如果是动态网站,会由controller处理(MVC),返回一个页面。
3.1 服务端重定向
有些服务端会把http重定向到https,这时,服务端会返回301或者302的状态码,并提供一个Location的响应头,这时浏览器会重新发起上述第二步开始进行。
3.2 响应数据类型
通过Content-type来区分是文件还是文本。
- text/html HTML格式
- application/octet-stream 字节流
4 连接阶段
4.2 等待TCP连接
http/1.1 一个tcp同时只能处理一个请求,浏览器会为每个域名维护6个tcp连接! 但是每个tcp连接是可以复用的,也就是处理完一个请求之后,不断开这个tcp连接,可以用来处理下个http请求! 不过http2是可以并行请求资源的,所以如果使用http2,浏览器只会为每个域名维护一个tcp连接
4.2断开连接
通常情况,一但服务端向客户端返回了数据,就要关闭TCP连接,不过可以通过添加头信息保持通道打开状态
Connection:Keep-Alive
5. 预渲染阶段
5.1 准备渲染进程
Chrome 的默认策略是,每个标签对应一个渲染进程。但如果从一个页面打开了另一个新页面,而新页面和当前页面属于同一站点的话,那么新页面会复用父页面的渲染进程。官方把这个默认策略叫 process-per-site-instance。
同一站点(same-site),Chrome会使用同一个渲染进程。
5.2 提交文档
浏览器进程将网路进程接受到HTML数据提交给渲染进程。
- 网络进程将资源下载完毕之后,告诉浏览器进程
- 浏览器进程向渲染进程发送“提交文档”的消息
- 渲染进程和网络进程建立传输数据的“管道”
- 文档数据传输完毕之后,渲染进程告诉浏览器进程“确认提交”的消息
- 浏览器进程更新UI界面中的状态,比如安全状态、地址栏的URL、前进后退的历史状态
6. 渲染阶段
6.1 构建DOM树
将HTML转为浏览器认识的DOM树,保存在内存中树状结构
6.2 样式计算
- 渲染引擎把CSS转为浏览器可以理解的结构——styleSheets
- 转换演示表中的属性值,使其标准化
- 计算每个DOM节点中的每个元素的具体样式,计算过程中遵循CSS的继承和层叠规则。(Computed Style)
6.3 布局阶段
- 遍历DOM树种可见元素,添加到构建布局树(LayoutTree)中
- 布局计算
- 分层。针对z-index、负责的3D转换、页面滚动等,渲染引擎还需要生成图层树(LayerTree)
- 图层绘制。把图层的绘制拆分成很小的绘制指令,然后再把这些绘制指令按照顺序组成绘制列表。
- 栅格化(raster)操作。
- 合成和显示。一旦所有的图块都被栅格化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。然后通过浏览器进程中名叫“viz”的组件,将页面绘制到内存中,最后再将内存显示到屏幕上。
操作解释|相关概念
分层
创建分层的条件:
- 拥有层叠上下文属性的元素会被提升为单独的一层,比如定位属性、透明属性、CSS滤镜等
- 需要剪裁的地方也会被创建为新的图层。文字超过div会被剪裁,如果出现滚动条,也会被提升为单独的图层
<style> div { width: 200px; height: 200px; overflow: auto; background: gray; } </style> <body> <div>123123123</div> <div> <p> 所以元素有了层叠上下文的属性或者需要被剪裁,那么就会被提升成为单独一层,你可以参看下图: </p> <p> 从上图我们可以看到,document层上有A和B层,而B层之上又有两个图层。这些图层组织在一起也是一颗树状结构。 </p> <p> 图层树是基于布局树来创建的,为了找出哪些元素需要在哪些层中,渲染引擎会遍历布局树来创建层树(Update LayerTree)。 </p> </div> </body>
栅格化
图层的绘制列表准备好之后,由浏览器主进程把列表提交(commit)给合成线程。
一个页面可能高度很高,显示器并不能完全显示网页的所有内容,而当前显示器所有显示的可见区域就叫做视口(ViewPort)。
合成线程会将图层划分为图块(tile),图块大小通常是256*256或者512*512。
合成线程会优先视口附近的图块来生成位图。栅格化的含义就是将图块转为位图。
重排
重绘
直接合成
可以避开重排和重绘阶段,直接在非主线程上执行合成动画操作,提升了绘制效率。