精确并自动化地获取页面首屏时间

本文发表在 微店前端团队 blog前端

做者:刘远洋git

公司:微店 - 前端团队github

日期:2018-03-05npm

背景

在前端性能数据的获取方法上,如今业内大多使用手动埋点的方式,即在代码中,人工判断首屏完成的位置,并在该处添加首屏记录的代码,相似:firstscreen.report() 这样。数组

这样作的简单省事,但缺点也很明显:bash

  • 和业务代码混用dom

    通用的监控需求混入了业务代码中前端性能

  • 覆盖不完整函数

    须要页面开发者自觉手动添加埋点代码,在业务中埋点覆盖率不必定能达到 100%工具

  • 准确性不必定高

    因为须要开发者自行判断统计脚本放置的位置,就会存在一些不许确的状况,由于每一个人对首屏的理解不一样

基于上面的分析,咱们近期尝试了一些方案,试图将首屏时间计算自动化,节省人力、并提升准确性。

定义

对首屏时间的定义,每一个公司可能会有所不一样,在本文中,首屏时间指的是:

  • 若是页面首屏有图片

    首屏时间 = 首屏图片所有加载完毕的时刻 - window.performance.timing.navigationStart
    复制代码
  • 若是页面首屏没有图片

    首屏时间 = 页面处于稳定状态前最后一次 dom 变化的时刻 - window.performance.timing.navigationStart
    复制代码

实现原理

整体思路为:

  • 从页面加载开始,按照必定的间隔打点,不断记录各个时刻下页面首屏图片列表和其余信息

    问题:按照怎样的间隔打点?

  • 找出页面首屏处于稳定状态的时刻 T1(到这个时刻为止,页面首屏可能已经稳定了一段时间)

    问题:如何找出这个 T1?

  • 以 T1 时刻的首屏图片数量为准,向前倒推,找到全部打点中最后一次和 T1 时刻首屏图片一致的打点时刻 T2

  • 统计 T2 时刻的全部图片加载完成时间 T3

  • T3 即为首屏完成的时刻,进行上报

下面,一个个解决上文中提到的问题:

  • 问题:如何找出首屏处于稳定状态的时刻 T1?

    咱们将页面从加载到渲染分为两大阶段:1. 获取数据;2. 数据获取完毕,渲染页面。

    这个逻辑符合绝大部分的页面逻辑:先获取数据,再渲染页面。

    解决方案:

    1. 经过 AOP 切面方式监听 XHR 的 send 对象,抓取页面中的第一个 XHR 请求,以第一个 XHR 请求发出的时刻为起点,统计在 1000ms 之内全部发出的请求到数组 Request 中。

      咱们认为可能影响首屏的请求在 [第一个 xhr 请求发出的时刻,第一个 xhr 请求发出的时刻 + 1000ms] 的时间段内均已发出。

    2. 针对串联型的请求(即下一个请求依赖上一个请求的返回数据),同时统计每一个请求返回后,500ms 之内新发出的请求到数组 Request 中。

      有些页面的数据请求方式是串行的,可能通过两个串联的请求后首屏的数据才能加载。

      影响首屏的请求可能也会以这样的形式发出。

    3. 数组 Request 中统计到的请求,基本包含了全部影响首屏的数据请求,同时也包含了部分不影响首屏的数据请求。

    4. 针对上述统计到的请求,找到全部数据返回的时刻 T1,而后,T1 = T1 + 300ms,保证页面接收数据后渲染完毕(300ms 用于一次渲染足够了)。

    5. 此时的 T1 时刻,页面首屏被认为处于稳定状态。

  • 问题:按照怎样的间隔打点?

    • MutationObserver

      你们都知道 MutationObserver 对象用于捕捉页面 dom 变化,所以在脚本中,咱们使用了 MutationObserver 监听 dom 变化,并在每次 dom 变化时触发一次打点(统计该时刻首屏图片信息)

    • setInterval

      setInterval 也能实现定时打点

    • MutationObserver 和 setInterval 组合

      但 MutationObserver 回调函数的触发时机开发者并不可控,有几种状况:

      • 两次回调之间可能距离几百毫秒甚至 1秒多,致使统计偏差较大
      • 某些状况下,dom 再也不变化,但页面元素中,imgsrc 发生了变化或元素的 background-image 发生了变化,并不会触发在 MutationObserver 的回调,致使统计失误

      所以,咱们如今的方案是结合 MutationObserver 和 setInterval,在 MutationObserver 回调的间歇,启动 setInterval,保证页面加载过程当中打点间隔不会过长,提升统计准确率。

统计偏差

即便使用了上述复杂的打点与判断,偏差仍然存在,那么,偏差到底在哪里?

以下图所示:

不稳定状态(1 images)   稳定状态2(2 images)      稳定状态1(2 images)
    |                        |                       |
    |________________________|_______________________|
    t1                       t2                      t3
复制代码

按照上面的理论,咱们会取 t2 时刻为能够统计首屏的时刻,两张图片加载完成的时刻即为首屏完成的时刻。

t2t1 时刻差了 1 张图片。

按照咱们的理论,首屏完成时间必定在 t2 以后的某个时刻 t2.n

而实际相差的那张图片,何时加载完成的,咱们不得而知,可能在 t2 前已经加载完毕了,也可能已经发出请求,但还没加载完毕。

偏差就在这里,它总会存在。

但咱们须要统计的是在偏差能够接受范围内的首屏数据,根据在公司业务实践的反馈来看,数据可靠性很高。

Talk is cheap, show me the code

咱们也开源了这个小工具:

github: auto-compute-first-screen-time

npm: auto-compute-first-screen-time

欢迎小伙伴们使用,吐槽,改进。

相关文章
相关标签/搜索