Last Surprise Lyn
  1. 1 Last Surprise Lyn
  2. 2 Life Will Change Lyn
  3. 3 Flower Of Life 发热巫女
  4. 4 Libertus Chen-U
  5. 5 Hypocrite Nush
  6. 6 Warcry mpi
  7. 7 One Last You Jen Bird
  8. 8 かかってこいよ NakamuraEmi
  9. 9 Time Bomb Veela
  10. 10 The Night We Stood Lyn
  11. 11 Quiet Storm Lyn
2018-10-31 00:13:26

漫谈前端数据监控

如果把一个应用比作人体,数据就相当于人体中的血液。无处不在,同样也无比重要。通过监控数据并分析其中带给我们的信息,能为应用的迭代或改进提供可靠的依据。

数据种类

那么在进入分析之前,需要知道数据种类也是多种多样的,不分类也不好将统计结果应用到实处。前端比较有价值的数据大致可以分为如下几类。

访问信息

这一类信息应该是最常规最普遍的信息,统计到的指标项一般会指导产品层面的设计。比较常见的指标项如下:

  • 访问量
  • 浏览器信息
  • 分辨率
  • 停留时长
  • 跳出率
  • 访问时间段

一般前端需要做的就是埋好点即可,这层数据更多层面的对大方向的产品设计有指导意义,比如根据用户浏览器兼容性参考决定一些新特性的使用,分辨率决定响应式设计的主要着重点等等。

性能

这对于前端来说就是相当重要的点了,更快的速度代表着更好的用户体验。通过对性能数据的监控可以发现应用的加载瓶颈,针对性的对代码进行优化。几个常见的指标如下。

  • 白屏时间:用户打开页面到有元素初次渲染为止,这其中占用的时间
  • 首屏时间:打开页面后不进行任何操作,所有内容都渲染出来所用的时间
  • 用户可交互时间:用户可以正常和页面交互(点击,输入等操作)的时间
  • 资源总加载时间:页面所有资源都加载完毕所花费的时间

异常

再厉害的程序员也不可能保证应用不出bug,虽然QA能发现发布大部分问题,但难免有应用上线后,经过各种特殊场景使用后才能发现的问题,那么我们就必须监控到这些异常,并对这些异常进行迅速的响应。以下是捕获到异常时通常需要记录的信息。

  • 异常的原始提示信息
  • 异常发生的文件位置
  • 异常发生的浏览器环境信息
  • 函数调用的堆栈信息

数据采集

针对以上三种数据来说,访问信息的数据相对好采集一些,一般浏览器都有提供大多数信息的相应API,这里主要说一下性能数据和异常数据的计算和采集手段。

性能

获取统计时间起点

性能数据基本上都和时间有关,JS和时间有关的操作通常都会想到Date对象,当然在通常情况下能满足大部分需求,但性能数据对精度的要求极高,该对象会受到系统时钟调整的影响,并且被限制在了一毫秒的精确度内,我们需要一种更高精度的时间计算方式来获取起点——Performance对象的now方法和timeOrigin属性。

  • performance.timeOrigin:返回当前页面浏览上下文第一次被创建的时间的高精度时间戳
  • performance.now:返回自timeOrigin后经过的毫秒数

有了高精度的参考系,下面就可以介绍测量性能数据的手段了,性能数据又可以细分为两类——资源加载性能和网页加载性能,不过在分别介绍这两者之前,还是要首先介绍它们的基础——性能时间线。

性能时间线

该对象拓展了Performance对象,提供了从性能时间线中获取性能指标的相关属性和方法。核心方法如下:

  • getEntries():返回所有性能入口对象
  • getEntriesByType():按类型过滤性能入口对象
  • getEntriesByName():按名称过滤性能入口对象

可以看到性能测量的核心就在于性能入口对象,性能入口对象就是用来描述某个阶段的性能信息的通用对象,上面提到的资源加载性能或者网页加载性能,都可以分为很多阶段,每个阶段的性能信息就是通过各自的入口对象描述,通用属性如下:

  • name: 当前阶段的标识符
  • entryType:当前阶段所属类型
  • startTime:当前阶段开始时的时间戳
  • duration: 当前阶段持续时间

有了这个通用的描述对象,下面就可以针对具体阶段分析各自的性能了。

资源加载性能模型

entryTyperesource的性能入口对象都属于该类,其拓展了性能入口对象,新增了很多描述资源获取阶段的统计信息,相关API可在PerformanceResourceTiming查阅。按资源获取来源的不同,下图中括号中的部分属性可能不可用。

网页加载性能模型

这也就是上一节谈到的几个常见指标计算所用到的模型了,其entryTypenavigation,其相关API可在PerformanceNavigationTiming查阅。时序模型如下图,根据这些name可以获取到精确的持续时间,再按照自己的需求计算出相关性能信息。

User Timing

利用以上API,我们可以精确测量浏览器常规阶段的性能信息,但对于整个应用来说,给予开发者自定义一些阶段并测量其中性能的灵活能力也是很重要的,基于此目的W3C定义了该规范。其同样是拓展了Performance对象,并提供了如下4个核心方法:

  • mark: 创建并存储一个PerformanceMark对象
  • clearMarks:清除给定名称的PerformanceMark对象
  • measure:测量两个PerformanceMark对象之间的持续时间并存储为PerformanceMeasure对象
  • clearMeasures:清除给定名称的PerformanceMeasure对象

这些方法创建的对象也都是基于性能入口对象的,使用上也是相当简单,mark打点记录执行到当前位置的性能,measure测量两点间性能。

异常

对于JS来说,本身有自己的一套简单的处理异常的能力,能保证应用的基本运行。大致流程如下:

  • JS线程从任务队列中循环提取任务执行
  • 当某一任务出现异常且没有被捕获时,沿着调用栈向外抛出,终止当前任务
  • 继续后续的任务队列循环

如果需要更精细的处理和监控异常,通常会基于如下两种方法实现。

try catch

该方法是前端比较常用的异常处理方法,只能捕获运行时错误,不能捕获语法和异步错误,一般用在编码时有感知可能出错并且不太容易避免的地方(浏览性兼容性问题等等),不适合应对未知的错误处理。

window.onerror

该方法可以捕获运行时错误和异步错误,也是主要用来捕获预料外的错误的方法。能够提供如下的错误信息

window.onerror = function(message, uri, line, column, error) {
    // message: 异常信息
    // uri: 异常文件路径
    // line: 异常行号
    // column: 异常列号
    // error:异常堆栈信息
}

需要注意的是,该方法捕获到的错误如果来自跨域文件或者压缩文件,如果要准确定位还需要相应的跨域和sourcemap处理。

埋点上报

现在我们已经有了收集数据的能力,下一步就要把数据上传到服务端供建模分析了。那么收集数据并上传的代码该如何集成到项目中呢?这一步所要做的,也就是前端埋点了。目前主要的埋点技术可以分为如下三类。

代码埋点

这种埋点方式应该是最直观,最容易想到的。简单来说就是哪里需要收集数据,就把收集数据的代码手工编入就可以了。算是最原始也是最精准的方案,编码形式也可以分为命令式和声明式两类。

// 命令式埋点
$('.button').click(() => {
    // 业务逻辑
    collectData(params);
});
/* 声明式埋点 */
<button data-collect="{id: '123', act: 'click'}"></button>

命令式埋点相比于声明式更灵活,但可读性和可维护性会更差点,不过在现在的各种View框架的加成下,声明式埋点的灵活度也有了很大提高。两者都有的劣势就是对业务代码的侵入性还是比较大的,每一次更新埋点信息的时候,都要修改大量代码。顺应着减小更新代价的需求,可视化埋点的方案也就应运而生。

可视化埋点

该类方案主要思路是在应用中引入相关封装好的SDK和后台配置界面进行关联,通过可视化配置设置采集节点和html元素进行关联,相当于把代码埋点的编码过程通用化插入。

那么好处是显而易见的,由于解耦了埋点逻辑和业务逻辑,就解决了埋点更新代价大的问题,也给予了非开发人员埋点的能力。缺点也就是通用和灵活从来不能两全,能收集到的数据和如何定制这套自动化SDK有关,可能大部分通用埋点场景都没有问题,在针对一些特殊的埋点场景还是需要代码埋点补充。

无埋点

既然对特定位置的埋点侵入代码有着维护麻烦的问题,那么干脆换个思路,全局收集所有数据信息就好了。这就是无埋点的思路,只需要全局加载自动全量采集并上报数据的SDK就可以了,简单粗暴但有效,不过问题也是很显然的,无差别的埋点上报增加了网络传输和服务器压力,如果要在业务复杂的项目上使用该方案是不得不考虑其带来的性能问题的。

-- EOF --

添加在分类「 前端开发 」下,并被添加 「性能优化」「工程化」 标签。