深入了解现代网络浏览器「译文」(二)

735 阅读8分钟

原文链接 developers.google.com/web/updates…

导航中会发生什么?

在上一篇文章中,我们研究了不同的进程和线程如何处理浏览器的不同部分。 在这篇文章中,我们深入探讨每个进程和线程如何通信以显示网站。

让我们看一个简单的 Web 浏览用例:您在浏览器中输入一个 URL,然后浏览器从 Internet 获取数据并显示一个页面。 在这篇文章中,我们将重点介绍用户请求站点和浏览器准备呈现页面的部分——导航。

从浏览器进程开始

正如我们在上篇文章(CPU、GPU、内存和多进程架构)所述:选项卡之外的所有内容都由浏览器进程处理。浏览器进程有一些线程,比如绘制浏览器按钮和输入框的 UI 线程、从 Internet 接收数据的网络线程、控制文件访问的存储线程等等。当您在地址栏中键入 URL 时,您的输入由浏览器进程的 UI 线程处理。

image.png 1:上边是浏览器UI,下边是浏览器进程图,其中包含UI、网络和存储线程\color{green} {图1:上边是浏览器 UI,下边是浏览器进程图,其中包含 UI、网络和存储线程}

一个简单的导航

1、处理输入

当用户开始在地址栏中输入内容时,UI 线程首先询问的是“这是搜索查询还是 URL?”。在 Chrome 中,地址栏也是一个搜索输入字段,因此 UI 线程需要解析并决定是将您输入的内容发送到搜索引擎,还是发送到您要请求的站点。

image.png 2UI线程询问输入的是搜索查询还是URL\color{green} {图2:UI 线程询问输入的是搜索查询还是 URL}

2、开始导航

当用户按下回车键时,UI 线程会发起网络调用来获取站点内容。 Loading spinner 显示在选项卡的一角,网络线程通过适当的协议,如 DNS 查找和为请求建立 TLS 连接。

image.png 3UI线程与网络线程通信,导航到mysite.com\color{green} {图3:UI 线程与网络线程通信,导航到 mysite.com}

此时,网络线程可能会收到服务器重定向 header,如 HTTP 301。在这种情况下,网络线程会与服务器请求重定向的 UI 线程通信。 然后,将发起另一个 URL 请求。

3、读取响应

一旦响应主体(有效负载)开始进入,网络线程会在必要时查看流的前几个字节。 响应的 Content-Type header 会说明它是什么类型的数据,但由于它可能丢失或错误,因此在这里完成 MIME 类型嗅探。正如源代码中所评论的那样,这是一项“棘手的业务”。 您可以阅读评论以了解不同浏览器如何处理内容类型/有效负载对。

MIME Type sniffing:媒体类型(也称为多用途 Internet 邮件扩展或 MIME 类型)是指示文档、文件或字节分类的性质和格式的标准。 它在 IETF 的 RFC 6838 中进行了定义和标准化。

image.png 4:包含ContentType和实际数据的有效负载的响应头\color{green} {图4:包含 Content-Type 和实际数据的有效负载的响应头}

如果响应是一个 HTML 文件,那么下一步就是将数据传递给渲染器进程,但如果它是一个 zip 文件或其他一些文件,那么这意味着它是一个下载请求,所以他们需要将数据传递给 下载管理器。

image.png 5:网络线程询问响应数据是否是来自安全站点的HTML\color{green} {图5:网络线程询问响应数据是否是来自安全站点的 HTML}

这也是安全浏览检查发生的地方。 如果域和响应数据似乎与已知恶意站点匹配,则网络线程会在页面中弹出警告框。此外,还会进行检查,阻止跨源读取(CORB),以确保敏感的跨站点数据不会进入渲染器进程。

4、查找渲染器进程

一旦完成所有检查,并且网络线程确定浏览器需要导航到的请求的站点,网络线程就会告诉 UI 线程数据已准备就绪。 UI线程然后找到一个渲染器进程来进行网页的渲染。

image.png 6:网络线程告诉UI线程查找渲染器进程\color{green} {图6:网络线程告诉 UI 线程查找渲染器进程}

由于网络请求可能需要数百毫秒才能获得响应,因此应用了加快此过程的优化。在第 2 步中,当 UI 线程向网络线程发送 URL 请求时,它已经知道他们要导航到哪个站点。UI 线程尝试与网络请求并行地主动查找或启动渲染器进程。这样,如果一切按预期进行,当网络线程接收到数据时,渲染器进程已经处于待机状态。如果导航重定向跨站点,则可能不会使用此备用进程,在这种情况下,可能需要不同的进程。

5、提交导航

现在数据和渲染器进程已经准备就绪,一个 IPC 从浏览器进程发送到渲染器进程以提交导航。 它还传递数据流,以便渲染器进程可以继续接收 HTML 数据。 一旦浏览器进程听到在渲染器进程中发生提交的确认,导航就完成了,文档加载阶段开始。

此时,地址栏已更新,安全指示器和站点设置 UI 反映了新页面的站点信息。 该选项卡的会话历史将更新,因此后退/前进按钮将逐步浏览刚刚导航到的站点。 为了在您关闭选项卡或窗口时便于选项卡/会话恢复,会话历史记录存储在磁盘上。

image.png 7:浏览器和渲染器进程之间的IPC,请求渲染页面\color{green} {图7:浏览器和渲染器进程之间的 IPC,请求渲染页面}

额外步骤:初始加载完成

提交导航后,渲染器进程会继续加载资源并渲染页面。 我们将在下一篇文章中详细介绍这个阶段发生的事情。 渲染器进程“完成”渲染后,它会将 IPC 发送回浏览器进程(这是在页面中的所有帧上触发所有 onload 事件并完成执行之后)。 此时,UI 线程停止选项卡上的加载器。

此“完成”非“完成”,在此之后客户端 JavaScript 仍然可以加载额外的资源并呈现新的视图。

image.png 8IPC从渲染器到浏览器进程通知页面已“加载”\color{green} {图8:IPC从渲染器到浏览器进程通知页面已“加载”}

导航到其他站点

简单的导航就完成了! 但是如果用户再次将不同的 URL 放入地址栏会发生什么? 好吧,浏览器进程通过相同的步骤导航到不同的站点。 但在此之前,它需要检查当前呈现的站点是否关心 beforeunload 事件。

beforeunload 可以创建“离开此站点?”的 alert 弹窗,当您尝试离开或关闭选项卡时发出警报。 选项卡内的所有内容(包括您的 JavaScript 代码)都由渲染器进程处理,因此当新的导航请求传入时,浏览器进程必须检查当前的渲染器进程。

注意:不要添加无条件的 beforeunload 处理程序。 它会产生更多的延迟,因为需要在导航开始之前执行处理程序。 仅在需要时才应添加此事件处理程序,例如:需要警告用户可能会丢失在页面上输入的数据。

image.png 9:从浏览器进程到渲染器进程的IPC告诉它即将导航到不同的站点\color{green} {图9:从浏览器进程到渲染器进程的 IPC 告诉它即将导航到不同的站点}

如果导航是从渲染器进程启动的(例如用户单击链接或客户端 JavaScript 运行 window.location = "https://newsite.com"),渲染器进程会首先检查 beforeunload 处理程序。 然后,它经历与浏览器进程启动导航相同的过程。 唯一的区别是导航请求从渲染器进程启动到浏览器进程。

当新导航到达与当前呈现的站点不同的站点时,将调用一个单独的渲染进程来处理新导航,同时保留当前呈现进程以处理unload等事件,有关更多信息,请参阅 page lifecycle states 以及如何使用page lifecycle states API 事件。

image.png 10:从浏览器进程到新渲染器进程的IPC通知渲染页面,并通知卸载旧渲染器进程\color{green} {图10:从浏览器进程到新渲染器进程的 IPC 通知渲染页面,并通知卸载旧渲染器进程}

Service Worker

最近对该导航过程的一项更改是引入了 Service Worker。 Service Worker 是一种在应用程序代码中编写网络代理的方法; Web 开发人员可以更好地控制本地缓存的内容以及何时从网络获取新数据。如果 Service Worker 设置为从缓存加载页面,则无需从网络请求数据。

要记住的重要部分是 Service Worker 是在渲染器进程中运行的 JavaScript 代码。 但是当导航请求进来时,浏览器进程如何知道该站点有 Service Worker

注册 Service Worker 后,Service Worker 的作用域将作为参考保留(您可以在这篇 The Service Worker Lifecycle 文章中阅读有关作用域的更多信息)。 当导航发生时,网络线程会根据已注册的 Service Worker 范围检查域,如果 Service Worker 已为该 URL 注册,则 UI 线程会查找渲染器进程以执行 Service Worker 代码。 Service Worker 可能会从缓存中加载数据,从而无需从网络请求数据,或者它可能会从网络请求新资源。

image.png 11:浏览器进程中的网络线程查找ServiceWorker\color{green} {图11:浏览器进程中的网络线程查找 Service Worker 域}

image.png 图12:浏览器进程中的UI线程启动渲染器进程来处理Service Worker渲染器进程中的工作线程然后从网络请求数据

导航预载

您可以看到,如果 Service Worker 最终决定从网络请求数据,浏览器进程和渲染器进程之间的这种往返可能会导致延迟。 Navigation Preload 是一种通过在 Service Worker 启动的同时加载资源来加速此过程的机制。 它用 header 标记这些请求,服务器可以为这些请求发送不同的内容; 例如,只是更新数据而不是整个文档。

image.png 13:浏览器进程中的UI线程启动渲染器进程来处理ServiceWorker,同时并行启动网络请求\color{green} {图13:浏览器进程中的UI线程启动渲染器进程来处理Service Worker,同时并行启动网络请求}

总结

在这篇文章中,我们研究了导航过程中发生的事情,以及您的 Web 应用程序代码(例如响应头和客户端 JavaScript)如何与浏览器交互。 了解浏览器从网络获取数据的步骤可以更容易地理解为什么开发导航预加载等 API。 在下一篇文章中,我们将深入探讨浏览器如何评估我们的 HTML/CSS/JavaScript 以呈现页面。

原文是google官方出版的,个人觉得可靠性高一点~ 大家知道如何在掘金中加入动态jpg图片不,留言给我~ 原文中有动图,可以帮助我们更好的理解~