XiaoboTalk

现代浏览器内部的一次 Navigation 流程

当在地址栏输入一个 URL 后,会发生什么,分别被哪些流程处理?
 

从 Browser Process 接收事件开始

一个 Browser Process 内部有三个主要工作的线程
  1. UI Thread:处理整个浏览器除 Dom 外的其他区域 UI 交换和事件。
  1. Network Thread:处理由整个浏览器发出的网络请求
  1. Storage Thread: 存储线程:控制本地相关文件的访问等。
 
一次 url 输入的流程大致如下:
  1. Browser 进程接管,并交给 UI 线程处理
  1. UI 线程接收到浏览器 输入框的内存。
    1. 判断是 google 搜索内容
    2. 还是 一个 URL,请求资源的定位符
    3. 浏览器 tab 开始转菊花,表示加载开始
  1. 对于 URL ,UI 线程创建一个 network 任务,准备请求一个网络请求内容。
  1. 然后 Network Thread 开始接管这个网络请求任务:
    1. 解析 DNS
    2. 建立 TLS 安全链接,发起请求
    3. 开始读取 Response 内容,分析 HEAD 和 Body (payload: 二进制载荷数据)
    4. 根据 Header 中的 ‘Content-Type’ 来解析二进制的 payload 数据。
    5. 跨域内容检查,安全控制 CSP 等。
  1. 如果是其他文件,例如 zip,则交给 下载管理器,去下载文件。
  1. 如果是 HTML 内容,Network Thread 的一切检查都合法的情况下,Network Thread 会把内容回调给 UI Thread。
  1. 然后 UI Thread 在去启动或者使用一个已有的 Render Process 去渲染 DOM
    1. 一般为了优化渲染速度,UI Thread 会再发送请求给 Network Thread 的同时,就并行(发)的开始或者找到一个可用的 Render Process。这样数据请求完成后,可以直接开始渲染。不需要等待启动渲染进程的完成。
    2. 数据通过 IPC 从 Browser Process 发给 Render Process。

DOM loading 阶段 (commit navigation)

一旦 Browser 进程已经确认:Render 进程开始处理相关的渲染工作。Browser 进程就会停止 tab 的菊花旋转,然后记录一个 history 栈 (back/forward)。准备好接受 Render Process 的结果。

卸载前 beforeunload event

如果整个过程中,用户再次输入重新定位到其他 URL,那么浏览器把上述流程重新做一遍,但是在这之前,会检查是否有 beforeunload 事件,如果有,则处理完成后,再进行下一轮处理和跳转。
  • 这是一个生命周期钩子函数,开发者可以注册:
    window.addEventListener('beforeunload', (event) => { event.preventDefault(); // 很关键 event.returnValue = ''; // 有些浏览器需要这样设置 });
    相当于浏览器在卸载当前页面的最后一步的回调,给用户一些重要提示等。
    • 这是一个同步事件,里边如果注册了异步任务,不会被处理。
     

    Service Worker

    一般一个 tab 会有一个独立的渲染进程 (Render Process),负责 DOM 树、CSS、JS 执行和绘制等。所以一般情况,Service Worker 的注册 (JS 代码) 都是在渲染进程进行的。
    那么 Browser Process 如何知道是否有 Service Worker 被注册了呢:通过 URL 注册域检查。
    • 每个 Service Worker 是绑定在一个 URL 上的
    • 浏览器进程的 Network Thread 会先检查某个请求是否有 Service Worker 注册,如果有。
    • 浏览器进程的 UI 线程让对应的渲染进程去执行这个 service worker 来返回网络请求数据。
      • 加载本地缓存,
      • 发起网络请求
    notion image
    • 事实上,与此同时,UI Thread 也会同时发起一个网络请求,让它和 Service Worker 共同工作。
      • 如果Service Worker 判断也需要进行网络请求 (过期或者其他)
      • 那么直接使用刚刚已经发起的网络请求结果
      • 这样达到最大的并行能力,节省时间。
    notion image