4、从输入URL到页面展示?----导航流程
- 浏览器进程--主要负责用户交互、子进程管理和文件储存等功能。
- 网络进程--是面向渲染进程和浏览器进程等提供网络下载功能。
- 渲染进程--主要职责是把从网络下载的 HTML、JavaScript、CSS、图片等资源解析为可以显示和交互的页面。因为渲染进程所有的内容都是通过网络获取的,会存在一些恶意代码利用浏览器漏洞对系统进行攻击,所以运行在渲染进程里面的代码是不被信任的。这也是为什么 Chrome 会让渲染进程运行在安全沙箱里,就是为了保证系统的安全。
从输入 URL 到页面展示
- 用户输入 —— 会判断是搜索内容还是URL,搜索内容会配合搜索引擎生成带搜索关键词的URL
离开当前页面时会有beforeunload事件,用户离开前可以执行一些操作 - URL 请求过程
进入了页面资源请求过程,浏览器进程会通过进程间通信(IPC)把 URL 请求发送至网络进程,
网络进程会查找本地缓存是否缓存了该资源。如果有缓存资源,那么直接返回资源给浏览器进程;
如果在缓存 中没有查找到资源,那么直接进入网络请求流程。
这请求前的第一步是要进行 DNS 解析,以获取 请求域名的服务器 IP 地址。
如果请求协议是 HTTPS,那么还需要建立 TLS 连接。
利用 IP 地址和服务器建立 TCP 连接,
连接建立之后,浏览器端会构建请求行、请求头等信息,该域名相关的 Cookie 等数据附加到请求头中,
然后向服务器发送构建的请求信息。
服务器接收到请求信息后,会根据请求信息生成响应数据(包括响应行、响应头和响应体等信息),
并发给网络进程。等网络进程接收了响应行和响应头之后,就开始解析响应头的内容了
(1)重定向
在接收到服务器返回的响应头后,网络进程开始解析响应头,如果发现返回的状态码是 301 或者 302,那么 说明服务器需要浏览器重定向到其他 URL。这时网络进程会从响应头的 Location 字段里面读取重定向的地址,然后再发起新的 HTTP 或者 HTTPS 请求,一切又重头开始了。
在导航过程中,如果服务器响应行的状态码包含了 301、302 一类的跳转信息,浏览器会跳转到新的地址继续导航;如果响应行是 200,那么表示浏览器可以继续处理该请求
(2)响应数据类型处理
Content-Type 是 HTTP 头中一个非常重要的字段, 它告诉浏览器服务器返回的响应体数据是什么类型
```js
Content-Type:text/html Content-Type:application/octet-stream // 字节流类型,通常浏览器会按下载类型处理 ```
如果Content-Type判断为下载类型,那么浏览器会交给下载管理器,URL请求的导航流程结束,如果是HTML,会继续进行。
- 准备渲染进程
通常Chrome 会为每个页面分配一个渲染进程, 但是如果协议名和根域名相同,会几个页面共用同一个渲染进程 - 提交文档
就是指浏览器进程将网络进程接收到的 HTML 数据提交给渲染进程,具体流程是这样的:
- 首先当浏览器进程接收到网络进程的响应头数据之后,便向渲染进程发起“提交文档”的消息;
- 渲染进程接收到“提交文档”的消息后,会和网络进程建立传输数据的“管道”;
- 等文档数据传输完成之后,渲染进程会返回“确认提交”的消息给浏览器进程;
- 浏览器进程在收到“确认提交”的消息后,会更新浏览器界面状态,包括了安全状态、地址栏的 URL、前进后退的历史状态,并更新 Web 页面。
到这里,一个完整的导航流程就“走”完了,这之后就要进入渲染阶段了。
- 渲染阶段
导航流程总结
- 服务器可以根据响应头来控制浏览器的行为,如跳转、网络数据类型判断。
- Chrome 默认采用每个标签对应一个渲染进程,但是如果两个页面属于同一站点,那这两个标签会使用同一个渲染进程。
- 浏览器的导航过程涵盖了从用户发起请求到提交文档给渲染进程的中间所有阶段。
导航流程很重要,它是网络加载流程和渲染流程之间的一座桥梁,如果你理解了导航流程,那么你就能完整串起来整个页面显示流程,这对于你理解浏览器的工作原理起到了点睛的作用。思考时
5、从输入URL到页面展示?----渲染流程
DOM 生成、样式计算、布局、分层
看一下他们三者关系
按照渲染的时间顺序,流水线可分为如下几个子阶段:构建 DOM 树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成
- 开始每个子阶段都有其输入的内容;
- 然后每个子阶段有其处理过程;
- 最终每个子阶段会生成输出内容。
(1)构建 DOM 树
这是因为浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构——DOM 树
(2)样式计算(Recalculate Style)
- 把 CSS 转换为浏览器能够理解的结构——styleSheets。(document.styleSheets)
- 转换样式表中的属性值,使其标准化(把属性值转为计算值)
- 计算出 DOM 树中每个节点的具体样式,涉及到 CSS 的继承规则和层叠规则
(3)布局阶段
计算DOM 树中可见元素的几何位置,我们把这个计算过程叫做布局。
创建布局树
DOM 树中还含有很多不可见的元素,比如 head 标签,还有使用了 display:none 属性的元素,
显示之前还需要在额外的构建一棵只包含可见元素的布局树。
(过滤掉不可见元素,遍历可见元素)
布局计算
计算布局树节点的坐标位置, 布局树既是输入内容也是输出内容,没有清晰的分离,下一代LayoutNG
(4)分层
页面中如果有复杂效果,滚动或者z-index排序,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树
元素有了层叠上下文的属性或者需要被剪裁,满足其中任意一点,就会被提升成为单独一层。
(5)图层绘制
把一个图层的绘制拆分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表
(6)栅格化(raster)操作
绘制操作是由渲染引擎中的合成线程来完成的,
当图层的绘制列表准备好之后,主线程会把该绘制列表提交(commit)给合成线程
合成线程会将图层划分为图块
合成线程通过姗格化按照视口附近的图块来优先生成位图
栅格化过程都会使用 GPU 来加速生成,使用 GPU 生成位图的过程叫快速栅格化,或者 GPU 栅格化,
生成的位图 被保存在 GPU 内存中。
渲染进程把生成图块的指令发送给 GPU,然后在 GPU 中执行生成图块的位图,并保存在 GPU 的内存中。
(7)合成和显示
一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。
浏览器进程里面有一个叫 viz 的组件,用来接收合成线程发过来的 DrawQuad 命令,然后根据 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。
渲染流水线大总结:
结合上图,一个完整的渲染流程大致可总结为如下:
- 渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构。
- 渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式。
- 创建布局树,并计算元素的布局信息。
- 对布局树进行分层,并生成分层树。
- 为每个图层生成绘制列表,并将其提交到合成线程。
- 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
- 合成线程发送绘制图块命令 DrawQuad 给浏览器进程。
- 浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上
重排(回流):
通过 JavaScript 或者 CSS 修改元素的几何位置属性,例如改变元素的宽度、高度等,那么浏览器会触发重新布局
需要更新完整的渲染流水线,所以开销也是最大的
重绘
如果修改了元素的背景颜色,那么布局阶段将不会被执行,因为并没有引起几何位置的变换,所以就直接进入了绘制阶段,重绘省去了布局和分层阶段,所以执行效率会比重排操作要高一些。
直接合成阶段
CSS 的 transform实现动画效果,可以避开重排和重绘阶段,直接在非主线程上执行合成动画操作。这样的效率是最高的,因为是在非主线程上合成,并没有占用主线程的资源,所以相对于重绘和重排,合成能大大提升绘制效率
为什么减少重绘、重排能优化 Web 性能吗
- 使用 class 操作样式,而不是频繁操作 style
- 避免使用 table 布局
- 批量dom 操作,例如 createDocumentFragment,或者使用框架,例如 React
- Debounce window resize 事件
- 对 dom 属性的读写要分离
- will-change: transform 做优化