输入URL到页面展示发生了什么
引言:根据当前所学的知识对这个经典面试题进行总结(还有很多地方后续完善),本文是一个知识骨架(所以很多详情图没有展示,都是文字描述),梳理了大体流程,从具体的流程中拓展出了我能想到的问题都后面有带有括号和序号,后续再进行一一补充。 大体来自极客时间的文章总结而来还有一些其他文章补充了一点细节。这里放上链接 05 | 渲染流程(上):HTML、CSS和JavaScript,是如何变成页面的? (geekbang.org)
——主要是浏览器和HTTP的层面
先放极客时间的流程图
图中显示三个进程相互配合完成,浏览器主进程,网络进程,渲染进程
看图解释过程:
用户输入信息->浏览器进程处理输入信息->开始导航->浏览器主进程通知网络进程发起URL请求->网络进程接收到响应报文,解析响应头字段后通知浏览器主进程准备渲染->主进程通知渲染进程开始提交文档阶段->渲染进程与网络进程建立传输数据管道,网络进程开始传输文档数据->渲染进程接收完文档数据后返回“确认提交”的消息给浏览器主进程->浏览器主进程接收到消息后更新浏览器界面状态->文档被确认提交后渲染进程开始拿文档进入页面解析和子资源加载->页面解析完成后渲染进程发送完成消息给浏览器进程->结束
主要过程
- 浏览器主进程用户输入请求信息
- 网络进程发起URL请求
- 浏览器在接收到响应报文后,准备渲染进程
- 提交文档阶段
- 渲染进程接受完文档信息后,解析和加载子资源
浏览器主进程用户输入请求信息
在浏览器主进程中用户在地址栏敲入回车后,浏览器便会检测输入的内容(url解析)
- 内容符合URL规则(01 HTTP:说说URL),若未完善地址栏则会帮你完善URL,如加上协议等
- 不符合则被认为是搜索内容,浏览器会使用默认引擎来合成新的URL
- 页面图标进入加载状态
(02 HTTP:为什么要解析URL,编码是?)
网络进程发起URL请求
发送的是HTTP请求,但众所周知HTTP over TCP,在发送HTTP请求前需要建立TCP连接,而TCP连接需要IP地址和端口,过程如下
- 构建请求
浏览器根据合成的URL来构建GET请求
(03 HTTP请求方法有,区别是)
- 查找缓存
在发起请求前浏览器会先查询自己的缓存(是否命中强缓存)
(04 HTTP:强缓存,协商缓存是,HTTP缓存策略)
- 准备IP地址和端口
TCP连接需要IP地址,我们已经有了URL,那么进入DNS解析获取IP地址
(05 DNS: DNS系统是,怎么解析的)
如果URL中没有指明端口,HTTP默认80端口,HTTPS默443端口
- 等待TCP队列
同一给域名下,Chrome浏览器最多建立六个TCP连接,如果多于这个数目,进入队列排队等待
(06 HTTP的队头阻塞是,解决方法)
- 建立TCP连接
三次握手建立
(07 TCP层面很多问题 :具体流程,为什么是三次握手....)
- 建立TLS连接(如果是HTTPS需要这个步骤)
HTTPS = HTTP over SSL/TLS
在发送HTTP请求前需要建立TLS连接
(08 HTTPS层面:SSL,TLS是;对称加密与非对称加密;数字签名与证书;连接过程是.....)
- 发送HTTP请求
浏览器把构建好的HTTP报文发送给服务器,充当正向代理(遮蔽用户发送请求)?
(09 HTTP:正向代理反向代理是;HTTP的代理相关头字段有...)
(10 HTTP层面很多问题: HTTP报文结构;传输过程,.....)
(11 HTTP:跨域问题)
- 传输过程
从应用层到网络层到装包,再从网络层到应用层拆包
(12 计算机网络:四层与七层,....)
- 服务器接收HTTP请求并处理
接收到请求后会进行处理,这里只学习了HTTP层面,如状态码的使用,缓存,Cookie相关,重定向,响应类型处理.....
(13 HTTP:常用的响应头字段以及作用)
- 浏览器接收响应报文
接收到响应报文
- 断开TCP连接
长连接?
(14 TCP: 四次挥手)
浏览器在接收到响应报文后,准备渲染进程
浏览器是多进程,默认情况下,浏览器会为每一个新页面创建一个新的渲染进程。但是在A页面打开B页面,A与B属于同一站点情况下,B会复用A的渲染进程(同一站点为根域名加上协议)
提交文档阶段
在准备渲染进程后,渲染进程在接收到浏览器主进程发出的提交文档消息后,开始进行提交文档阶段:与网络进程建立传输管道,接收网络进程发送的文档(响应体数据),接收完后发送确认提交给浏览器主进程。
浏览器进程收到确认提交后更新浏览器界面状态,包括安全状态,地址栏URL,前进后退的历史状态,并进行更新Web页面(页面先空白)
渲染阶段
处理流程称为渲染流水线。流水线分为多个子阶段,有以下特点
- 开始每个子阶段都有其输入的内容
- 每个子阶段都有其处理过程
- 最终每个子阶段都会生成输出内容
tip:这一套流水线的操作单位是帧,意味着每一帧渲染流水线都会走一遍。
子阶段如下:
- DOM树创建
如上文所述特点,每个子阶段都有输入,DOM树创建的输入内容就是HTML文件,经HTML解析器解析,输出DOM树
DOM树是根据HTML保存在内存的树状结构,可以通过JS来查询或者修改内容。
- 样式计算
我们已经拿到了DOM树,现在要开始CSS文件的样式计算阶段。
样式计算分为三个步骤:转化成styleSheets;styleSheets属性值标准化;计算出DOM树每个节点的具体样式
-
转化成styleSheets
与HTML一样,浏览器也会先进行转换操作,CSS文本会被转化成styleSheets。转化后三种来源的CSS文件都会被整理成一个styleSheets(link标签外部引用,style嵌入,行内),并且已经整理成了浏览器能够理解的结构。
(15 CSS:CSS引入方式和优先级)
-
styleSheets属性值标准化
css属性值有很多类型,就比如font-size属性值可以用px,em,rem..
像em,rem这两个属性值对于渲染引擎来说不是很好理解,但是px很容易,所以要把所有的属性值都标准化。
(16 CSS:em,rem,移动开发布局..)
- 计算出每个DOM树中每个节点的具体样式
计算样式关系到两个重要规则:继承,层叠
继承就是子节点带有父节点的属性,CSS有的属性带有继承,有的属性不继承。设置某个节点的可继承属性,其子节点也会继承下去,子节点的子节点也会..有点递归的意味。
(17 CSS:css继承属性与非继承属性)
层叠是CSS的⼀个基本特征,它是⼀个定义了如何合并来⾃多个源的属性值的算法。它在CSS处于核⼼地位,CSS的全称“层叠样式表”正是强调了这⼀点。
(18 CSS:层叠规则,层叠上下文)
- 布局树创建和布局计算
布局树创建:现在有了DOM树和样式表,现在这个阶段需要去除不可见的元素节点(displya:none意味着不需要渲染),经过遍历DOM树的所有可见节点合成出了布局树。
布局计算:有了布局树,每个节点样式是有了,现在要开始计算每个节点的坐标位置了。经过布局计算,每个节点在哪已经确定下来。
- 分层树创建
有了布局树,每个元素的具体位置出来了,但是页面展示实际上上是多图层的(用于3D动画,z轴排序..),所以还需要对各个元素进行分层。
有的节点会直接生成一个图层,不生成图层的节点则继承父节点的图层。那么什么节点会生成图层呢?
1 拥有层叠上下文的元素会被单独提升为单独的一层(18 CSS:层叠规则,层叠上下文)
2.产生裁剪的元素产生图层
3.不裁剪出现滚动条的话,滚动条也会被提升为单独的层。
- 图层绘制
每一层都划分完毕,现在可以进行绘制,绘制的步骤叫绘制指令,渲染引擎会把所有的这些要执行的指令按顺序组成一个待绘制列表
至此前五个操作都是在主线程进行,现在主线程会将绘制表通过commit提交给合成线程
- 栅格化操作
现在合成进程开始实际的绘制操作,有的图层很大,所以合成进程会将图层划分为多个图块,而将图块生成位图的操作就叫做栅格化操作。合成线程会按照视口附加的图块优先生成位图,栅格化操作有两个操作进行:
-
GPU进程内进行(IPC通信),称为GPU栅格化(使用GPU可以加速生成位图,也叫快速栅格化),生成的位图都会被保存在GPU内存中
-
栅格化线程池中进行,当没有GPU或者GPU资源占满,渲染进程则会维护一个栅格化的线程池来进行栅格化生成位图
-
合成和显示
合成:所有图块一旦被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将命令提交给浏览器进程
显示:浏览器进程⾥⾯有⼀个叫viz的组件,⽤来接收合成线程发过来的DrawQuad命令,然后根据DrawQuad命 令,将其⻚⾯内容绘制到内存中,最后再将内存显⽰在屏幕上。
(19 浏览器: 重绘和重排;如何优化)
未完,欢迎各位大佬进行指正和补充。