阅读 2313

[译]从内部了解现代浏览器(2)

原文Mariko Kosaka

[译]从内部了解现代浏览器(1)

[译]从内部了解现代浏览器(2)

[译]从内部了解现代浏览器(3)

导航会发生什么

这是本系列博客的第2部分。在上一篇文章中,我们研究了不同的进程和线程如何处理浏览器的不同部分。在这篇文章中,我们将深入研究每个进程和线程如何进行通信以显示网站。

让我们看一下Web浏览的简单用例:您在浏览器中键入URL,然后浏览器从Internet获取数据并显示页面。在这篇文章中,我们将重点关注用户请求网站的部分以及浏览器准备呈现页面的部分 - 也称为导航。

从浏览器进程开始

正如我们在 第1部分中所述:CPU,GPU,内存和多进程架构,选项卡外部的所有内容都由浏览器进程处理。浏览器进程具有诸如UI线程之类的线程,其绘制浏览器的按钮和输入字段,处理网络堆栈从互联网接收数据的网络线程,控制对文件的访问的存储线程等。当您在地址栏中键入URL时,您的输入将先由浏览器进程的UI线程处理。

图1:浏览器UI、网络和存储线程

一个简单的导航

1.处理输入

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

图2:UI线程询问输入是搜索查询还是URL

2.开始导航

当用户点击回车时,UI线程启动网络调用以获取站点内容。加载标志显示在选项卡的一侧,网络线程通过适当的协议,如DNS 为请求来查找和建立TLS连接。

图3:UI线程与网络线程通信以导航到mysite

此时,网络线程可以接收像HTTP 301这样的服务器重定向头。比如,当服务器请求重定向时,网络线程会与UI线程通信,然后启动另一个URL请求。

3.读取服务器响应

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

图3:包含Content-Type和有效载荷的响应头

如果响应是HTML文件,那么下一步就是将数据传递给渲染器进程,但如果它是zip文件或其他文件,则表示它是下载请求,因此需要将数据传递给下载管理器。

图4:网络线程询问响应数据是否是来自安全站点的HTML

这也是SafeBrowsing检查发生的地方。如果域和响应数据似乎与已知的恶意站点匹配,则网络线程会发出警告以显示警告页面。此外, 还会发生Cross Origin Read Blocking(CORB)检查,以确保敏感的跨站点数据无法进入渲染器进程。

4.查找渲染器进程

完成所有检查并且网络线程确信浏览器应导航到所请求的站点后,网络线程会告知UI线程数据已准备就绪。然后,UI线程找到渲染器进程以进行网页的渲染。

图5:网络线程与ui线程

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

5.提交导航

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

此时,地址栏会更新,安全指示器和站点设置UI会反映新页面的站点信息。选项卡的会话历史记录将被更新,因此后退/前进按钮也会被应用新的记录。为了在关闭选项卡或窗口时简化选项卡/会话还原,会话历史记录会存储在磁盘上。

图6:浏览器进程和渲染器进程间的ipc,请求渲染页面

最后,初始化加载完成

提交导航后,渲染器进程继续加载资源并呈现页面。 我们将在下一篇文章中详细介绍现阶段的情况。 一旦渲染器进程“完成”渲染,它就会将一个IPC发送回浏览器进程(这是在所有onload事件触发了包含页面中的所有框架,并且完成执行event handler之后)。 此时,UI线程会停止选项卡上的加载标志。 我说的“完成”,因为客户端JavaScript仍然可以加载额外的资源并在此之后呈现新的视图。

图7:渲染器进程告知浏览器进程渲染完成

导航到其他的站点

简单的导航到此已经完成,但是当用户在地址栏再次键入了其他的地址将会发生什么呢?是的,浏览器进程会进行相同的步骤去导航到不同的网址;但是,在这之前,浏览器进程会检查当前被渲染的网站是否具有beforeupload

beforeupload会创建一个“你确定要离开此站点”的警告当你想导航到其他的站点或者关闭这个标签;你的所有javascript代码将被渲染器进程处理,所以浏览器进程必须在新导航进入的时候检查当前的渲染器进程;

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

图8:浏览器进程告知渲染器进程导航将要变更

如果导航是从渲染器进程启动的(如用户单击链接或客户端JavaScript已运行window.location =“newsite.com”),则渲染器进程首先检查beforeunload处理程序。 然后,它进行与浏览器进程启动导航相同的步骤。 唯一的区别是导航请求从渲染器进程到浏览器进程触发的。

当新导航进入与当前渲染不同的站点时,将调用单独的渲染过程来处理新导航,同时保持当前渲染过程以处理卸载等事件。 有关更多信息,请参阅页面生命周期状态概述以及如何使用Page Lifecycle API钩子事件。

图9:浏览器告知渲染器进程需要渲染页面和卸载页面

service worker

最近有关导航的一个改变是引入了service worker链接)。service worker是一种在应用程序代码中编写网络代理的方法; 允许Web开发人员更好地控制本地缓存内容以及何时从网络获取新数据。如果将service worker设置为从缓存加载页面,则无需从网络请求数据。

重要的是service worker是在渲染器进程中运行的JavaScript代码。但是当导航请求进入时,浏览器进程如何知道该站点有service worker

图10:浏览器进程中的网络线程检查service worker注册域

注册service worker时,将保留service worker的范围作为参考(您可以在此“service worker生命周期”一文中阅读有关范围的更多信息)。当导航发生时,网络线程根据注册的service worker范围检查域,如果为该URL注册了service worker,则UI线程找到渲染器进程以执行service worker代码。service worker可以从缓存加载数据,无需从网络请求数据,或者可以从网络请求新资源。

图11:浏览器进程中的UI线程启动渲染器进程以处理service worker; 然后,渲染器进程中的工作线程从网络请求数据

导航的预加载

您可以看到,如果service worker最终决定从网络请求数据,则浏览器进程渲染器进程之间的往返可能会导致延迟。 导航预加载( Navigation Preload)是一种通过与service worker并行加载资源来加速此过程的机制。 它会标记这些请求,允许服务器决定为这些请求发送不同的内容; 例如,只更新数据而不是完整文档。

图12:浏览器进程中的UI线程启动渲染器进程以在并行的启动网络请求的同时处理service work

总结

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

关注下面的标签,发现更多相似文章
评论

查看更多 >