Chrome DevTools 中的网络面板
网络面板中单个请求的时间线:
解释
- Queueing(排队时间):
浏览器加载资源是有优先级的(优先加载 HTML、CSS、JS),其他的请求要为这些资源加载”让路“。
同时,Chrome 为每个域名维护 6 个 TCP 连接,发起 HTTP 请求时,这几个 TCP 连接都处于忙碌状态,就会处于排队状态。 - Stalled
在发起连接之前,有一些其他原因导致推迟,这就是 Stalled 时间。 - Initial connection/SSL
和服务器建立连接,包括建立 TCP 连接,以及 HTTPS 协议的 SSL 握手时间。 - Request sent
将浏览器缓冲区的数据发送出去。(可以忽略不计) - Waiting (TTFB)
第一字节时间,表示从连接发出去到收到服务器响应的第一字节的消耗时间。表现服务器响应能力。 - Content Download
从第一字节之后,到完整接收服务器响应内容所消耗时间。
优化
- Queueing(排队时间)过久
采用域名分片技术(扩充域名)或是升级至 HTTP2 (没有 TCP 连接数的限制了)。 - 第一字节时间(TTFB)过久
- 提升服务器的处理速度
- 采用 CDN 解决网络延迟
- 优化请求头
- Content Download 过久
减少单个请求的内容大小。
渲染流程
渲染流程图(侧重在构建 DOM 树阶段)如下:
DOM 树的构建
通过网络进程获取到的 HTML 字节流,持续不断地输送给渲染进程的 HTML 解析器:
- 分词,同时维护一个 Token 的栈,用来辅助 DOM 树的生成
- 构建 DOM 树
影响 DOM 构建的因素
- 遇到内联的 script 标签,需要停止 DOM 的构建,等到 JS 执行完再继续;遇到需要加载外部 script 的文件,需要先下载,再执行;
- 如果页面中有引入外部的 CSS 文件,同时又引入了外部的 JS 的文件,需要先下载 CSS 文件,再构建 CSSOM,然后才能执行 JS 文件;
- Chrome 会在 HTML 数据响应之后,开启一个预解析线程,用来下载 HTML 文件中的 CSS 和 JS 文件;
页面白屏时间
- 输入 URL 到网络进程响应内容
这一阶段主要受网络和服务器的影响较大
- JS 执行阻塞 DOM 的构建
这一阶段主要是因为 CSS 和 JS 文件的下载,以及 JS 文件的执行
如何减少页面白屏时间(第二个)
- 将 CSS 和 JS 内联,排除文件的下载时间干扰。但是这样的做法只适用于部分场景,因为内联会导致 HTML 的体积变大,增加第一个白屏时间
- 通过 webpack 打包工具,减小 CSS 和 JS 文件体积大小,主要做法是压缩和去除注释
- 将首屏不需要的 JS 文件,标记上 async 或 defer,使他们不阻塞 DOM 的构建
- 将 CSS 文件按照不同的场景进行拆分,避免首次全量加载
渲染引擎的分层和合成机制
为了提升渲染的效率,浏览器中的页面会分成很多个”层“,类似于 PS 中的图层。合成操作是将这些图层合并到一起。
分层是在布局树构建之后,渲染引擎会根据布局树的特点将其转换为层树,层树是渲染流水线后续流程的基础。
合成操作是在合成线程中进行的,不会影响到主线程。所以有时候主线程卡住了,但是 CSS 动画依然能够执行。
利用分层技术优化代码
如果用 JS 来实现动画的话,会牵扯到整个渲染流程,效率十分低下。可以利用分层机制来优化动画的实现:
1 | .box { |
使用 will-change 来提前申明会对该元素做哪些操作。渲染引擎会将该元素单独实现一层,等变换发生时,通过合成线程去处理变换,没有涉及到主线程,大大提升了渲染效率。
如何系统的优化页面
主要是优化处在加载阶段和交互阶段的页面。
加载阶段
- 减少关键资源的个数
- 缩小关键资源的体积
关键资源指的是影响首屏加载的各类资源(HTML、CSS 文件)。
通过以上两个方法,来减少关键资源的 RTT 时间。
交互阶段
- 减少 JS 的执行时间
通过函数任务的切分,让脚本不要一次霸占主线程太长时间
- 避免强制同步布局和布局抖动
避免将计算样式和布局操作提前到当前任务当中,主要是由修改完 DOM 之后立即查询 DOM 属性导致的。布局抖动指的是,在一段 JS 代码执行过程中,反复执行布局操作。不过目前使用现代的前端框架(React、Vue 等),已经避免了这样的问题。
- 合理利用 CSS 合成动画
因为合成动画是在合成线程上执行的,不会占用主线程,而且合成线程合成动画的效率很高。
- 避免频繁的垃圾回收
减少临时对象的创建,避免小颗粒对象的产生。