0%

浏览器工作原理学习笔记(五)-浏览器中的页面

Chrome DevTools 中的网络面板

网络面板中单个请求的时间线:
Markdown

解释

  1. Queueing(排队时间):
    浏览器加载资源是有优先级的(优先加载 HTML、CSS、JS),其他的请求要为这些资源加载”让路“。
    同时,Chrome 为每个域名维护 6 个 TCP 连接,发起 HTTP 请求时,这几个 TCP 连接都处于忙碌状态,就会处于排队状态。
  2. Stalled
    在发起连接之前,有一些其他原因导致推迟,这就是 Stalled 时间。
  3. Initial connection/SSL
    和服务器建立连接,包括建立 TCP 连接,以及 HTTPS 协议的 SSL 握手时间。
  4. Request sent
    将浏览器缓冲区的数据发送出去。(可以忽略不计)
  5. Waiting (TTFB)
    第一字节时间,表示从连接发出去到收到服务器响应的第一字节的消耗时间。表现服务器响应能力。
  6. Content Download
    从第一字节之后,到完整接收服务器响应内容所消耗时间。

优化

  1. Queueing(排队时间)过久
    采用域名分片技术(扩充域名)或是升级至 HTTP2 (没有 TCP 连接数的限制了)。
  2. 第一字节时间(TTFB)过久
    • 提升服务器的处理速度
    • 采用 CDN 解决网络延迟
    • 优化请求头
  3. Content Download 过久
    减少单个请求的内容大小。

渲染流程

渲染流程图(侧重在构建 DOM 树阶段)如下:
Markdown

DOM 树的构建

通过网络进程获取到的 HTML 字节流,持续不断地输送给渲染进程的 HTML 解析器:
Markdown

  • 分词,同时维护一个 Token 的栈,用来辅助 DOM 树的生成
  • 构建 DOM 树

影响 DOM 构建的因素

  1. 遇到内联的 script 标签,需要停止 DOM 的构建,等到 JS 执行完再继续;遇到需要加载外部 script 的文件,需要先下载,再执行;
  2. 如果页面中有引入外部的 CSS 文件,同时又引入了外部的 JS 的文件,需要先下载 CSS 文件,再构建 CSSOM,然后才能执行 JS 文件;
  3. Chrome 会在 HTML 数据响应之后,开启一个预解析线程,用来下载 HTML 文件中的 CSS 和 JS 文件;

页面白屏时间

  1. 输入 URL 到网络进程响应内容

    这一阶段主要受网络和服务器的影响较大

  2. JS 执行阻塞 DOM 的构建

    这一阶段主要是因为 CSS 和 JS 文件的下载,以及 JS 文件的执行

如何减少页面白屏时间(第二个)

  • 将 CSS 和 JS 内联,排除文件的下载时间干扰。但是这样的做法只适用于部分场景,因为内联会导致 HTML 的体积变大,增加第一个白屏时间
  • 通过 webpack 打包工具,减小 CSS 和 JS 文件体积大小,主要做法是压缩和去除注释
  • 将首屏不需要的 JS 文件,标记上 async 或 defer,使他们不阻塞 DOM 的构建
  • 将 CSS 文件按照不同的场景进行拆分,避免首次全量加载

渲染引擎的分层和合成机制

为了提升渲染的效率,浏览器中的页面会分成很多个”层“,类似于 PS 中的图层。合成操作是将这些图层合并到一起。
分层是在布局树构建之后,渲染引擎会根据布局树的特点将其转换为层树,层树是渲染流水线后续流程的基础。
合成操作是在合成线程中进行的,不会影响到主线程。所以有时候主线程卡住了,但是 CSS 动画依然能够执行。

利用分层技术优化代码

如果用 JS 来实现动画的话,会牵扯到整个渲染流程,效率十分低下。可以利用分层机制来优化动画的实现:

1
2
3
.box {
will-change: transform, opacity;
}

使用 will-change 来提前申明会对该元素做哪些操作。渲染引擎会将该元素单独实现一层,等变换发生时,通过合成线程去处理变换,没有涉及到主线程,大大提升了渲染效率。

如何系统的优化页面

主要是优化处在加载阶段和交互阶段的页面。

加载阶段

  • 减少关键资源的个数
  • 缩小关键资源的体积

    关键资源指的是影响首屏加载的各类资源(HTML、CSS 文件)。
    通过以上两个方法,来减少关键资源的 RTT 时间。

交互阶段

  • 减少 JS 的执行时间

    通过函数任务的切分,让脚本不要一次霸占主线程太长时间

  • 避免强制同步布局和布局抖动

    避免将计算样式和布局操作提前到当前任务当中,主要是由修改完 DOM 之后立即查询 DOM 属性导致的。布局抖动指的是,在一段 JS 代码执行过程中,反复执行布局操作。不过目前使用现代的前端框架(React、Vue 等),已经避免了这样的问题。

  • 合理利用 CSS 合成动画

    因为合成动画是在合成线程上执行的,不会占用主线程,而且合成线程合成动画的效率很高。

  • 避免频繁的垃圾回收

    减少临时对象的创建,避免小颗粒对象的产生。