需要重点留意的是 service worker 只是一些跑在渲染进程里面的 JavaScript 代码。那么当有一个导航请求过来,浏览器进程是如何知道有一个 service worker 的呢?
当 service worker 在注册的时候,它的作用范围(scope)被当成一个实例被记录下来(欲了解更多,阅读 The Service Worker Lifecycle ),在导航开始的时候,网络线程会根据请求的域名在已经注册的 service worker 作用范围里面寻找有没有对应的 service worker 实例,如这个 URL 有注册过,UI 线程将寻找一个渲染引擎来执行它的代码,这样,service worker 可能使用之前缓存的数据,也可能发起新的网络请求。
上文理解了相关概念之后,本文我们将开始研究这些进程和线程之间发生了什么,如何显示一个网站内容。
我们从一个经典的面试题说起:在浏览器中输入 URL 并点回车后,浏览器内部究竟发生了什么?(also known as a navigation)
一切从浏览器进程开始 通过前文的知识我们知道,在浏览器 Tab 以外发生的操作都是由 browser process 控制的,浏览器进程常见的一些线程为:
A simple navigation
第一步:处理输入
当用户在导航栏输入信息的时候 UI 线程要进行一系列的解析,用来判定是将用户输入信息发送给搜索引擎还是直接请求你输入的站点资源。
第二步:开始导航
当按下回车后,UI 线程将初始化网络请求并返回站点内容,此时 Tab 前的图标展示为加载中状态,然后网络进程进行一系列诸如 DNS 寻址,建立 TLS 连接等操作进行资源请求。这时如果收到服务器的 HTTP 301 重定向响应,它将会告知 UI 线程进行重定向然后它会再次发起一个新的网络请求。
第三步:读取响应
一旦响应体开始响应返回,在必要的情况下它会先检查一下流的前几个字节,然后根据响应头中的 Content-Type 字段来确定响应主体的媒体类型(MIME Type),不过 Content-Type 有时候会缺失或者是错误的。
如果响应体是一个 HTML file,则将响应数据交给渲染进程来进行下一步的工作,如果是 zip 压缩文件或者其它类型的文件,这意味着是一个下载请求,则会把相关数据传输给下载管理器。
这也是浏览器会进行 SafeBrowsing 检查发生的地方,如果请求的域名和响应的内容匹配到某个已知的病毒站点,网络线程将给用户展示一个警告的页面。除此之外,网络线程还会做 Cross Origin Read Blocking(CORB)检查来确定那些敏感的跨站数据不会被发送至渲染进程。
第四步:寻找渲染进程
一旦做完各种检查以后,网络线程确信浏览器可以导航到请求的站点,网络线程将告诉 UI 线程所有数据已经准备完毕,UI 线程接下来寻找一个渲染引擎来渲染页面。
网络请求是有耗时的,浏览器需要对查找渲染进程这一步骤进行优化。在第二步开始,浏览器已经知道要导航的站点,那么 UI 线程预加载一个渲染进程,如一切符合预期则直接用渲染引擎渲染页面即可,否则,如果遇到重定向,这个准备好的渲染进程也许就用不到了,它会被摒弃,这时将会重启一个渲染进程。
第五步:提交导航
到这一步的时候,数据和渲染引擎都已经准备好了,浏览器进程通过 IPC 通知渲染进程去提交本次导航,除此之外,浏览器进程还会将刚刚接收到的响应数据流传递给对应的渲染进程让它继续接收到来的 HTML 数据,一旦浏览器进程监听到渲染引擎的导航已经被提交的消息,则导航这个过程就结束了,进入到文档的加载阶段。
到了这个时候,导航栏会被更新,安全指示符(地址前面的小锁)和站点设置 UI(site settings UI )会被更新,会话历史列表(history tab)也会被更新,这样即可以通过前进后退来切换该页面。
额外的步骤:初始化加载完成
一旦导航(navigation)完成提交,渲染引擎开始着手加载资源以及渲染页面,后续的文章将继续介绍渲染细节。一旦渲染引擎完成渲染,它会通过 IPC 告知浏览器进程(页面及内部的 iframe 页面都触发了 onload 事件),到这个点,UI 线程将停止加载转圈。
欲了解更多,请关注或阅读 an overview of page lifecycle states 和 the Page Lifecycle API。
In case of Service Worker
service worker 可以用来做网络代理或者缓存控制,目的在于给开发者更多的控制权限。
需要重点留意的是 service worker 只是一些跑在渲染进程里面的 JavaScript 代码。那么当有一个导航请求过来,浏览器进程是如何知道有一个 service worker 的呢?
当 service worker 在注册的时候,它的作用范围(scope)被当成一个实例被记录下来(欲了解更多,阅读 The Service Worker Lifecycle ),在导航开始的时候,网络线程会根据请求的域名在已经注册的 service worker 作用范围里面寻找有没有对应的 service worker 实例,如这个 URL 有注册过,UI 线程将寻找一个渲染引擎来执行它的代码,这样,service worker 可能使用之前缓存的数据,也可能发起新的网络请求。
总结
本文讨论了导航具体都发生了哪些事情以及浏览器优化导航效率采取的一些技术方案,下文继续了解浏览器如何解析 HTML/CSS/JavaScript 并渲染页面的。