(译)浏览器渲染原理 - 导航

504 阅读6分钟

导航

浏览器进程

选项卡外部的所有内容都由浏览器进程处理。浏览器进程包含多个线程,例如以下的几个线程:

  • ui 线程负责浏览器中的按钮和输入框;
  • 网络线程处理网络堆栈中的请求,以实现通过网络协议从服务器获得数据;
  • 存储线程控制对文件的访问权限;

线程间如何进行通信的

另一个直观的问题: 简述从输入url到页面呈现, -> 从进程的角度可以拆分为两个部分来看: 一部分: 从输入URL,处理网络请求,到获得数据的过程,这部分中间的一系列的过程称为浏览器进程的导航(navigation) 第二个部分是: 拿到数据到页面呈现,这部分是渲染进程来处理。

UI 线程处理输入

当用户开始输入地址栏时,UI 线程首先要判断的是 “这是搜索查询还是 URL?”。 因为在 Chrome 中,地址栏也是搜索输入框,因此 UI 线程需要解析并判断是将你的输入发送到搜索引擎还是去请求对应的网站。

开始导航发起网络请求

当用户按下回车,ui线程负责选型卡loading展示,同时UI thread与network process 之间通过IPC(Inter Process Communication)通信, network process 发起网络请求获取服务端资源数据。 网络线程(network thread)通过域名解析(DNS 解析)为网络IP(IPv4,IPv6),经过网络层处理,到达传输层,(经过3次握手)建立 TLS 连接。 如果Network process 收到服务端请求的重定向,比如 HTTP 301,这种情况下 浏览器的进程(UI 线程)与网络进程通信会修改重定向的URL。

解析response 头部执行安全check

当接收到有效的response body 部分(payload)后,network process 查看http 报文的前几个字节(header的部分),response header中的Content-Type 表明是什么类型。如果响应是 HTML 文件,那么才将数据传递给渲染器(renderer)进程, 如果它是 zip 文件或其他文件,则表示它是一个下载请求,因此需要将数据传递给下载管理器. 同时,浏览器的安全检查开始做一些防护,如检测网站是否是恶意站点,如果是恶意站点,网络线程发出警告以显示警告页面。此外还有cors(Cross Origin Read Blocking)的检测。确保敏感不安全的跨域信息不会渲染。

找到可用渲染进程

解析response 头部并执行安全check检测后确保是可渲染的html数据,network thread才与浏览器进程通信,navigate导航到请求的网站,网络线程通知 UI 线程已经拿到数据,然后ui 线程找到可用的渲染进程渲染页面数据.

由于网络请求一般是异步的,可能需要几百毫秒才能得到响应,对上述过程做了加速的优化。 当 UI 线程在第 2 步通知网络线程发起URL 请求时,ui thread已经知道接下来可能将要导航到哪个站点。 UI 线程并行做以上两部分工作:1:通知网络线程发起请求,2, 找到可用的渲染进程。一般情况下,获得网络请求的数据后渲染进程已经是就绪状态了。

提交 navigation,完成导航

当数据通过安全检测,浏览器进程将提交导航(commit the navigation))的信息通过IPC(Inter Process Communication)通知渲染进程,就意味着导航已经完成。这一过程浏览器的ui 线程会负责完成以下更新:

  • 地址栏中的安全标示,

  • 站点图标ui展示

  • 选项卡的会话历史记录前进后退刷新状态标示

  • 完成初始加载

提交导航之后,渲染进程开始渲染页面,一旦渲染进程完成页面的渲染,会给浏览器进程发出IPC (只是针对unload事件的完成),然后 ui 线程会停止tab 页面的loading的加载标示。

以上就是正常情况下导航,以下是一些其他情况的处理:

导航到不同站点

如果用户再次在地址栏中输入不同的 URL,这种情况下会发生什么呢?好,浏览器进程会通过以上步骤导航到不同的站点, 但是,在做这之前,还需要检查当前正在渲染的站点,会不会触发beforeunload事件, 这个事件会有 "Leave this site?" 的弹框。 上面提到过标签页内的内容(包含异步的js 操作)都是由渲染进程负责的,所以当新的导航请求发生时,浏览器进程会与渲染进程进程通信进行通信确认新的导航请求。

如果从渲染器进程启动导航(例如用户点击链接或执行 window.location =“newsite.com”),那么渲染器进程会首先检查 beforeunload 的处理。 然后,执行上面浏览器进程启动导航的过程。 唯一的区别是导航请求从渲染器进程发送到浏览器进程。

当新导航进入的站点与当前渲染的站点不同时,将会调用另一个单独的渲染进程来处理新导航,同时当前的渲染进程以处理当前渲染的站点的事件如: unload 等事件。 an overview of page lifecycle states and the Page Lifecycle API.

service worker

近来随着SW的流行, 导航也做了些调整。SW 是在你的应用中写网络代理的方式,使用SW开发者可以更加灵活控制本地缓存内容以及何时从网络获取新数据,如果 service worker 设置为从缓存加载页面,则无需从网络请求数据。

sw是通过js 来实现, 是运行在渲染进程中的。所以,当导航发起请求后,浏览器进程是如何知道这个站点是配置来SW了呢?带着这个疑问来看:

  • 当sw 被注册后,在站点域下会有sw的引用。
  • 当导航启动后,网络进程根据注册的 Service Worker 检查域,如果当前URL 注册了 Service Worker,则 UI 线程找到渲染器进程来执行 Service Worker 代码。 Service Worker 也可以从缓存加载数据,无需从网络请求数据,也可以从网络请求新资源。
Navigation Preload

当Service Worker 从网络请求数据的情况下,浏览器进程和渲染器进程之间的往返通信可能会导致延迟。 导航预加载可以加速此过程的机制,他可以与 Service Worker 并行加载资源。 利用 header 标记这些请求,允许服务器为这些请求发送不同的内容,例如:只更新部分数据而不是整个文档的情况。

总结

到此,最开始的问题: 从输入url到页面呈现, -> 从进程的角度可以拆分为两个部分来看: 一部分: 从输入URL,处理网络请求,到获得数据的过程,这部分中间的一系列的过程称为浏览器进程的导航(navigation)

这个部分的处理已经说完了,下一节是第二部分。

原文链接