• Home
  • Archives
  Evan的博客
  • Home
  • Archives
  • 面试
  • 原理笔记
  • 项目实践
  • 其他

白屏优化与性能指标

2020/10/09 posted in  面试 项目实践

工作中接到一个需求,需要对首屏的性能数据做分析。于是调研了一遍 performance API,并且结合实际情况做了一些性能数据埋点的实践。

performance API 介绍

performance API 可以用来追踪请求页面时的整个生命周期不同阶段的耗时。通过 window.performance.timing 可以获得所有的耗时数据。

主要埋点属性

image

网络连接相关属性:

  1. navigationStart
    浏览器接收到 url 开始跳转的时间,如果有前页面,与前页面卸载的时间相等

  2. domainLookupStart
    开始查询 DNS 的时间

  3. domainLookupEnd
    DNS 查找完成时间

  4. connectStart
    网络层 ip 协议走完,开始传输层 TCP 握手

  5. connectEnd
    建立起 tcp/ip 连接的时间

  6. secureConnectionStart
    发起 TLS 握手的时间,包括 CA 证书认证时间

资源下载相关属性:

  1. requestStart
    万事俱备,开始发起 http 数据包

  2. responseStart
    收到第一个数据包的时间

  3. responseEnd
    收到最后一个数据包的时间

    注意这里仅仅指的是 html 文档,也就是我们说的入口文件

DOM 构建与脚本解析相关属性:

  1. domLoading
    已经拿到了 html,开始解析 dom 的时间,也就是开始读<html> 标签的时间

    MDN 的解释:When the parser started its work, that is when its Document.readyState changes to 'loading' and the corresponding readystatechange event is thrown.

  2. domInteractive
    dom 树解析完成的时间

    html 读完,但是可能部分内嵌如 script defer 资源未加载,这个时候如果终止 dom 解析(比如按掉浏览器的 x)如果 html 是有内容的,其实是可以交互的,只是没有样式和脚本不全而已

    MDN 的解释:When the parser finished its work on the main document, that is when its Document.readyState changes to 'interactive' and the corresponding readystatechange event is thrown.

image

  1. domContentLoadedEventStart
    所有资源获取完成,js 解析阶段完成,进入运行时 runtime 的开始时间

    这个阶段在 DOMContentLoaded 事件触发之前

    MDN 的解释:Right before the parser sent the DOMContentLoaded event, that is right after all the scripts that need to be executed right after parsing have been executed.

  2. domContentLoadedEventEnd
    脚本执行完成,抛出 DOMContentLoaded 事件,也是 domReady 的时间

    大多数知名库如 jquery 都是用这个节点来判断 dom 构建结束

    MDN 的解释:Right after all the scripts that need to be executed as soon as possible, in order or not, have been executed.

  3. domComplete
    所有资源加载完成,包括 ajax,图片等异步请求,此时抛出 onload 事件回调

    即浏览器的 http 异步进程,追踪定时器 setInterval 的进程,异步回调 setTimeout 等进程都闲置时

  4. loadEventStart
    onload 回调事件开始执行

  5. loadEventEnd
    onload 回调事件执行完毕

中间还有一些暂时对我们来说用不上的打点,就不详细解释了,比如本地缓存命中时间,href 重定向时间等,可以去看MDN

根据上述属性,大致分成三个阶段

网络初始化阶段

requestStart - navigationStart

包括浏览器处理时间(初始化,卸载前页,重定向等)和网络连接时间(DNS,TCP/IP,TLS 等)

资源下载阶段

responseEnd - requestStart

脚本解析及渲染阶段

domContentLoadedEventEnd - domLoading

  • 注意!这一阶段并不单纯是本地执行时间,还包含<script>和<link>的网络请求,简单来说:这是除 html 之外的资源下载时间 + DOM 树构建时间 + CSSOM 构建时间 + 渲染树合成时间 + 合成层定位 + JS 解释阶段 + JS runtime 的时间总合

计算白屏时间和首屏时间

  • 白屏时间
    domContentLoadedEventEnd - navigationStart

    • domContentLoadedEventEnd 也就是 DOMContentLoaded 触发的时间,即客户端捕获上报的时间节点。客户端和大多数监控(包括很多知名的第三方库)用这个数据作为作为白屏时间和 domReady 的时间节点,但是对我们应用来说这并不是十分准确
    • 我们是路由按需加载的单页应用,domContentLoadedEventEnd 针对的是 html 文件和其中内嵌资源进行的监控,而我们页面是通过 js 去控制切换的,也就是说次页面的监控用 domContentLoadedEventEnd 是监测不到的(因为不会重新请求一个 html)
    • 按正常单页应用来说,其实也不用管次屏,因为首次 html 就会把所有依赖的 js 下载下来,后续是不会再去请求控制渲染的 js 的,都是本地代码的切换。但是我们为了减小首包大小,采用了路由按需加载的策略,也就是第一次不会下载次页面资源,只有当路由切换的时候再去请求,然而这个请求不是请求 html 而是请求 js,这就让 domContentLoadedEventEnd 监测不到了,可以参考谷歌用户体验追踪的文档
  • 页面完全加载时间
    domComplete - navigationStart

这个就是浏览器 Network 面板中 Load 触发的时间。但是 domComplete 这个时间节点是不包含onload事件回调的触发和执行时间的,如果要涵盖 onload 回调的时间,就要用loadEventEnd - navigationStart这个时间

更有意义的数据指标

做完需求之后我在想,获取到首屏 / 白屏数据之后,对业务真的有意义吗?或许有一定帮助,但是我觉得并不实用。

先说白屏数据,我觉得业务关心白屏数据并没有什么意义

比如对一个电商的商品详情页来说,我渲染了商品名称。但是因为某种网络原因其他资源下载失败了。这时候白屏数据已经拿到了,但用户其实更想看到商品的详情,图片等信息,而这些数据没有拿到。

再说说首屏数据,首屏是完全加载完包括 ajax 等资源,这个数据也不是业务想关心的

比如用户看完了商品详情,但是就是有一个 icon 的图片下载失败了。这时候对用户而言,他所关心的资源其实都看到了,已经无所谓这个小 icon 了

所以我们需要拿到的,有意义的数据,其实应该是用户想要看到的数据,而不是单纯的白屏或者首屏这么简单

获取更硬核的数据指标

我在查阅了相关资料之后,发现有一个 API 或许能有一定帮助:MutationObserver API

简单来说就是当 DOM 结构发生改变的时候,这个 API 能执行一个回调。

那我们就可以给不同的 DOM 元素附上一个权重,比如商品详情页,主图权重高一些,商品名称和详情介绍权重高一些;比如订单确认页,付款按钮权重高一些,价格信息权重高一些等。

然后去分析这个页面渲染到某个权重值的时候的时间节点。当然这个权重配置因人而异。由于我并没有实际做过企业级的操作,在这里就只提供一个思路。

« CSS 硬件加速

常见 JS 面试题 »

Evan的博客

Evan 的博客 - 非典型码农,bug永动机
Instagram Weibo GitHub Email RSS

Categories

面试 原理笔记 项目实践 其他 JS Vue 性能优化 算法 计算机网络

Recent Posts

  • 从 HTTP 发展历程重学计算机网络
  • 应届前端的逆袭(中)
  • 应届前端的逆袭(上)
  • 应届前端的逆袭(下)
  • 前端面经复盘

Copyright © 2015 Powered by MWeb,  Theme used GitHub CSS.