从url输入地址到最终网页渲染,中间发生了什么?
1. DNS查询 / 解析
- 将域名地址解析成ip地址
- 浏览器DNS缓存
- 计算机DNS缓存
- 路由器DNS缓存
- 网络运营商DNS缓存
2. TCP连接: TCP三次握手
-
第一次握手:浏览器发送给服务器,告诉服务器我准备好了,将要发送请求
-
第二次握手:服务器发送给浏览器,告诉浏览器我也准备好了,需要和你再次确认一下
-
第三次握手:浏览器发送给服务器,告诉服务器确认完毕,马上发送请求
Connection: keep-alive 保持长连接(保持TCP连接)
3. 发送请求
按照HTTP协议的规定,生成请求报文,浏览器将请求报文发送给服务器
浏览器将请求报文发送给服务器
4. 返回响应
按照HTTP协议的规定,生成相应报文,服务器将请求报文发送给客户端
5. 渲染页面: 见下文↓
6. 断开连接:TCP四次挥手
第一次挥手:浏览器发送给服务器,告诉服务器请求报文发送完毕
第二次挥手:服务器发送给浏览器,告诉浏览器请求报文接受完毕,可以等待断开
第三次挥手:服务器发送给浏览器,告诉浏览器响应报文发送完毕
第四次挥手:浏览器发送给服务器,告诉服务器响应报文接受完毕,可以断开连接了
服务器断开连接 再是浏览器断开连接
浏览器渲染
-
构建 DOM 树
- 因为浏览器无法直接理解和使用 html 文件,所以需要将 html 文件转为浏览器能够理解的结构 DOM 树
- 输入:html 文件
- 输出:DOM 树
- 操作过程:解析 html 结构为浏览器可以理解的 DOM 树结构,期间会去下载次级资源以及执行 js 代码。
-
样式计算
样式计算是为了获取每个节点的样式,其主要分为三步来完成。
-
转成浏览器可以理解的数据结构styleSheets,可以在开发者工具上通过 document.styleSheets 打印出来。只需要了解到主进程会将 css 代码转成浏览器可以理解的结构,这个结构支持查询和修改。可以在开发者工具上通过 document.styleSheets 打印出来。
-
将 css 转成标准化的样式
比如 rem 转成 px、bule 转成 rgba 等。
-
最后是计算每个节点的样式。
这一步骤涉及到 css 的继承规则和层叠规则。有些属性是可以被子元素继承的,有些属性是会覆盖前面的样式
-
-
布局阶段
想要渲染一个完整的页面,仅知道 DOM 树和 DOM 树元素的样式还是不够的,我们还需要知道 DOM 树中元素的位置。同样的布局这个子阶段也分为两个过程操作,分别是合成布局树和计算节点位置。
-
合成布局树
布局树和 DOM 树类似,不过布局树上只包含会显示的节点内容,不包含 display: none 样式的元素。只包含可见节点
-
计算节点位置
有了一颗完成的布局树,主线程会计算出每个元素的位置信息以及盒子大小
-
-
分层
因为页面有很多复杂的效果,比如滑动、z-idnex 等。为了更好的实现这些效果,渲染引擎主线程还需要为特定的阶段生成专用的图层,并生成一颗对应的图层树。
-
拥有层叠上下文属性的元素会单独生成一个图层。
- 3D 或透视变换的 css 属性
- 使用加速视频解码的 video 元素
- canvas 元素
- opacity 属性
-
需要裁剪的地方也会单独生成一个图层
裁剪就是需要滚动的地方,里面内容会单独生成一个图层。如果有滚动条,滚动条也会单独生成一个图层
-
-
图层绘制
在完成图层树的构建之后,渲染引擎主线程会对每个图层进行绘制。这里说的绘制不是真正的绘制画面,而是生成一个绘制指令列表。
将每个图层的绘制拆分成多个绘制指令,传给合成线程。
-
栅格化
绘制指令生成之后,渲染进程主线程会将绘制指令发送给合成线程,由合成线程来完成最后的绘制工作。合成线程会将图层划分为图块。
-
合成和显示
等所有图块都被栅格化,合成线程会收集位图信息来创建合成帧。合成帧随后会通过 IPC 协议将消息传给浏览器主进程。浏览器主进程收到消息后,会将页面内容绘制到内存中,最后再将内存显示在屏幕上。