前端监控一般分为三种,分别为页面埋点、性能监控以及异常监控。

页面埋点

页面埋点应该是大家最常写的监控了,一般起码会监控以下几个数据:

  • PV / UV
  • 停留时长
  • 流量来源
  • 用户交互

对于这几类统计,一般的实现思路大致可以分为两种,分别为手写埋点和无埋点的方式。

相信第一种方式也是大家最常用的方式,可以自主选择需要监控的数据然后在相应的地方写入代码。这

种方式的灵活性很大,但是唯一的缺点就是工作量较大,每个需要监控的地方都得插入代码。

另一种无埋点的方式基本不需要开发者手写埋点了,而是统计所有的事件并且定时上报。这种方式虽然

没有前一种方式繁琐了,但是因为统计的是所有事件,所以还需要后期过滤出需要的数据。

性能监控

性能监控可以很好的帮助开发者了解在各种真实环境下,页面的性能情况是如何的。

对于性能监控来说,我们可以直接使用浏览器自带的 Performance API 来实现这个功能。
performance 是一个全局对象。我们在控制台里输入 window.performance,就可一窥其全貌:

关键时间节点

在 performance 的 timing 属性中,我们可以查看到如下的时间戳:

这些时间戳与页面整个加载流程中的关键时间节点有着一一对应的关系:

通过求两个时间点之间的差值,我们可以得出某个过程花费的时间,举个🌰:

const timing = window.performance.timing
 // DNS查询耗时
 timing.domainLookupEnd - timing.domainLookupStart// TCP连接耗时
 timing.connectEnd - timing.connectStart// 内容加载耗时
 timing.responseEnd - timing.requestStart

···

const timing = window.performance.timing
// DNS查询耗时
timing.domainLookupEnd - timing.domainLookupStart
  
// TCP连接耗时
timing.connectEnd - timing.connectStart
 
// 内容加载耗时
timing.responseEnd - timing.requestStart

···

除了这些常见的耗时情况,我们更应该去关注一些关键性能指标:firstbyte、fpt、tti、ready 和 load 时间。这些指标数据与真实的用户体验息息相关,是我们日常业务性能监测中不可或缺的一部分:

// firstbyte:首包时间 
 timing.responseStart – timing.domainLookupStart// fpt:First Paint Time, 首次渲染时间 / 白屏时间
 timing.responseEnd – timing.fetchStart// tti:Time to Interact,首次可交互时间 
 timing.domInteractive – timing.fetchStart// ready:HTML 加载完成时间,即 DOM 就位的时间
 timing.domContentLoaded – timing.fetchStart// load:页面完全加载时间
 timing.loadEventStart – timing.fetchStart

以上这些通过 Performance API 获取到的时间信息都具有较高的准确度。我们可以对此进行一番格式处理之后上报给服务端,也可以基于此去制作相应的统计图表,从而实现更加精准、更加个性化的性能耗时统计。

此外,通过访问 performance 的 memory 属性,我们还可以获取到内存占用相关的数据;通过对 performance 的其它属性方法的灵活运用,我们还可以把它耦合进业务里,实现更加多样化的性能监测需求——灵活,是可编程化方案最大的优点。

异常监控

对于异常监控来说,以下两种监控是必不可少的,分别是代码报错以及接口异常上报。

对于代码运行错误,通常的办法是使用 window.onerror 拦截报错。该方法能拦截到大部分的详细报错信息,但是也有例外

  • 对于跨域的代码运行错误会显示 Script error. 对于这种情况我们需要给 script 标签添加 crossorigin 属性
  • 对于某些浏览器可能不会显示调用栈信息,这种情况可以通过 arguments.callee.caller 来做栈递归

对于异步代码来说,可以使用 catch 的方式捕获错误。比如 Promise 可以直接使用 catch 函数,async await 可以使用 try catch

但是要注意线上运行的代码都是压缩过的,需要在打包时生成 sourceMap 文件便于 debug。

对于捕获的错误需要上传给服务器,通常可以通过 img 标签的 src 发起一个请求。

另外接口异常就相对来说简单了,可以列举出出错的状态码。一旦出现此类的状态码就可以立即上报出

错。接口异常上报可以让开发人员迅速知道有哪些接口出现了大面积的报错,以便迅速修复问题。