浏览器输入 URL 后发生了什么?

lxf2023-03-12 16:57:01

在搜索 EventLoop 时无意看到了 这篇文章:inside-browser(chrome),中间过程描述地很清晰细腻。详细看完本篇后,希望能轻松应对这类“在浏览器输入 URL 后发生了什么?”面试题

浏览器中进程和线程的构成

Browser 进程:UI 线程,Network 线程,GPU 线程

以 Chrome 举例,当我们打开浏览器时,便创建了 Browser 浏览器进程 ,内部会启动 UI 线程 , Network 线程 对用户输入的 URL 地址做页面跳转,以及负责后续的资源加载。

Renderer 进程:Main 线程,Compositor 线程,Raster 线程

页面的渲染会通过 Renderer 渲染进程 进行,整个过程通过 Main主线程 来串连。渲染的内容会涉及 Compositor 线程 和 Raster 线程 。 下面针对 在浏览器输入 URL 后发生了什么?  这一问题,列举几个重要的步骤进行说明:

第1步:地址栏输入地址

当打开浏览器后会创建一个 Browser 进程 ,用户在地址栏中输入文字后,浏览器的 UI 线程(UI thread)  将解析输入的内容,并判断到底是一个 URL 还是普通词语,已决定后续的调用方式

浏览器输入 URL 后发生了什么?

第2步:开始导航跳转

当回车确认的内容为 URL 后,将开启一个 tab 标签页。同时 网络线程(network thread)  将开始工作:开始 DNS 寻址以及建立 TLS 传输通道。

浏览器输入 URL 后发生了什么?

第3步:解析 Response 信息,进行安全检测

根据 Response 信息中的 Content-Type 响应头来判断该数据资源属于哪种 媒体类型,比如:text/html、image/png... 同步,浏览器还会开启安全监测,用来告知用户哪些链接是危险链接,给与警告提示:

浏览器输入 URL 后发生了什么?

像我们页面里 script ,img 会引用有来自不同域名的资源,浏览器提供 CORB 政策来对这些资源做安全监测。

第4步:开启渲染进程,完成导航跳转

一旦浏览器的检查工作完成后, 网络进程 也知道哪些资源会实现链接的跳转, UI 线程 将主动寻找可用的或开启 渲染进程(renderer thread)  。 资源加载的同时, UI 线程 会以 IPC 的方式将返回数据同步通知给 Renderer 渲染进程 。当 渲染进程 内部完成页面的渲染工作后, 将通知浏览器完成导航跳转 。

浏览器输入 URL 后发生了什么?


Renderer 进程中的过程

Renderer 渲染进程 较为复杂,全览下整体过程,下面在分步做解释。

浏览器输入 URL 后发生了什么?

第5步:解析 DOM Tree,加载外部依赖

在 Browser 进程 中,我们已经通过 网路线程 获取到的页面资源——HTML,同时并发送数据给了 Renderer 渲染进程。  Renderer 进程 会通过 主线程 按 HTML Standard 规范将内容转化为 DOM 文档对象模型 。

浏览器输入 URL 后发生了什么?

在解析过程中,途径 link,script 标签, network 线程 将访问所引用的文件。如果文件有一定的访问时间,或者 js 有处理时间,将会阻断 DOM 的解析,也就是我们俗称的“页面白屏”。

第6步:计算样式

加载完 css 文件后, main 主线程 会拿 DOM 中的节点和样式进行匹配,生成 Computed Style 。

浏览器输入 URL 后发生了什么?

第7步:流式布局 Flow

由于光知道 DOM 节点数和样式信息也不足以渲染页面, 主线程 会根据这两者继续生成 LayoutBlock Flow,

浏览器输入 URL 后发生了什么?

多个 LayoutBlock Flow 组成了 LayoutTree 渲染树 。 Layout 渲染树 可能和 DOM 树 一样,但因为 display:none,或者一些 css 伪元素的 content 定义和 DOM 树 有差异。不同的 LayoutBlock Flow 会根据当前元素的 几何属性 确认了互相间的“距离”,从而在从上至下的排序中,调整好布局方式。

浏览器输入 URL 后发生了什么?

第8步:绘制 Paint

当有了 Layout 渲染树 还不能进行页面展示,我们还需要对每个 LayoutBlock Flow 布局的流块继续加工,包含:各种颜色,position 坐标,通过 z-index 定义的图层,绘制的文字等信息。 最终 LayoutBlock Flows 会被转化为 Paint Records 绘制记录,以在 合成环节 中使用。

浏览器输入 URL 后发生了什么?

第9步:合成 Compositing

我们在代码里定义的 px,屏幕并不知道是什么,将通过一套规则将其转为计算机懂的东西。 这套规则就是 合成 :我们所要展示的页面将被分割为多个 layers 图层 进行渲染,每个图层由 compositor thread 印刷线程 解析 Paint Records 绘制信息进行光栅化(将矢量形状转换为位图形式)处理后的内容组成。如果页面滚动将重新对图层进行光栅化。 为得到 layer 图层 , main 线程 要将 Layout Tree 转化为** Layer Tree 图层树**:

浏览器输入 URL 后发生了什么?

一旦上述工作完成后, main 线程 会告知 compositor 排版线程,它会将内容交给 raster 线程 进行光栅化(rasterizes),然后交给GPU处理。

浏览器输入 URL 后发生了什么?

处理完这些内容(tiles)后, compositor 线程 将创建 compositor frame 排版帧,帧内的内容称为 draw quads 绘制好的四方格。 最后, compositor 线程 会通过 IPC 告知 Browser 进程 ,将 draw quads 交给 UI线程 ,以及 GPU 线程 。我们的屏幕会根据 60fps 刷新并展示所接收到的排版帧,页面的样子就一点点渲染出来了。

总结

这张图是在搜索“回流,重绘”概念文章中 频繁出现 的“老面孔”,相信在了解上述几步的运行机制后会对这图有自己的新理解。

浏览器输入 URL 后发生了什么?

最后提几个小问题,希望大家能触类旁通:

  • 为什么 html 和 css 的解析是分开的?
  • DOM 树 和 Style 样式 合成什么东西?
  • 布局,绘制内部到底在做什么?
  • 最后屏幕上的展示内容又是怎么呈现在我们的面前?

参考

  • Inside look at modern web browser (part 2): https://developer.chrome.com/blog/inside-browser-part2/
  • Inside look at modern web browser (part 3): https://developer.chrome.com/blog/inside-browser-part3/
  • Cross-Origin Read Blocking for Web Developers: https://www.chromium.org/Home/chromium-security/corb-for-developers/
  • Eliminate content repaints with the new Layers panel in Chrome - LogRocket Blog: https://blog.logrocket.com/eliminate-content-repaints-with-the-new-layers-panel-in-chrome-e2c306d4d752/?gi=cd6271834cea
  • Stick to Compositor-Only Properties and Manage Layer Count: https://web.dev/stick-to-compositor-only-properties-and-manage-layer-count/

欢迎在公众号“爱吃手的诗小雨”中与我交流