前端监控SDK开发| 青训营笔记

79 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 9 天

什么是前端监控

在浏览器里,从输入 URL 到页面展示,这中间发生了什么?

image-20230207132517614.png

前端监控就是尽可能的采集这一过程以及后续用户交互中产出的性能指标与发生的异常事件并上报到平台完成消费。

为什么需要前端监控

让我们从用户(浏览网页的人)的视角来抛出一些使用时遇到的问题:

  • 网页打开好慢 ------页面某个关键资源渲染太慢。
  • 网页卡顿---------页面同步计算任务太重,阻塞渲染。
  • 网页图片裂开------客户端网络状态差,或上游服务节点异常。
  • 网页白屏-----------页面脚本执行失败、关键资源加载失败、请求失败等。

前端监控到底监控了什么

  • 性能指标

  • 异常行为

  • 用户行为

image-20230207133601861.png

以用户为中心的性能指标

image-20230207140622230.png

image-20230207134405035.png

  • FP (First Paint):首次渲染的时间点。FP 时间点之前,用户看到的都是没有任何内容的白色屏幕。
  • FCP (First Contentful Paint):首次有内容渲染的时间点。
  • FMP (First Meaningful Paint):首次绘制有意义内容的时间点。
  • TTI (Time to Interactive):测量页面从开始加载到主要子资源完成渲染,并能够快速、可靠地响应用户输入所需的时间。
  • TTI反映页面可用性的重要指标。TTI值越小,代表用户可以更早地操作页面,用户体验就更好。
  • Sl (Speed Index):衡量页面可视区域加载速度,帮助检测页面的加载体验差异。
  • FID (First Input Delay):测量从用户第一次与页面交互(比如当他们单击链接、点 按按钮等等)直到浏览器对交互作出响应,实际能够开始处理事件时处理程序所经过的时间
  • LCP (Largest Contentful Paint)最大的内容在可视区域内变得可见的时间点。
  • TBT (Total Blocking Time):量化主线程在空闲之前的繁忙程度,有助于理解在加 载期间,页面无法响应用户输入的时间有多久。
  • CLS (Cumulative Layout Shift):量化了在页面加载期间,视口中元素的移动程度。

常见异常

静态资源错误

  • 静态资源:加载页面所需的 html、 css 和js 等文件,以及其他各类多媒体文件,如图片、音频和视频等
  • 静态资源错误:在拉取和加载静态资源的过程中发生了预期之外的错误,如网络异常等,导致静态资源无法正常渲染到页面上。

请求异常

100-199 ---------> 信息响应

200 - 299 ----------> 成功响应

300 - 399 ---------> 重定向消息

400 - 499 ---------> 客户端错误响应

500 - 599 ----------> 服务端错误响应

状态码0是什么

image-20230207143114708.png

JS错误

在页面运行时发生的Js 错误会严重影响页面的正常渲染与交互,是前端监控的重点。

image-20230207143342281.png

白屏异常

前面几类异常都可以通过浏览器提供的标准化方法来监听到,而白屏异常没有标准化的监听方法,所以更考验前端监控开发者的功底。

通常我们可以通过判断 DOM 树的结构来粗略的判断白屏是否发生。

监听到白屏发生后,我们还需要对白屏的发生进行归因,

通常导致白屏发生的原因可能有如下几点:

  • 发生 Js 错误导致关键资源渲染失败。
  • 请求异常或静态资源加载失败。
  • 长时间的 Js 线程繁忙阻塞渲染任务。

性能指标监控

  • 利用 Performance 和PerformanceObserver 可以监控到一些标准的渲染性能数据

参考链接

code

function createPerfMonitor(report: ({ name: string, data: any }) => void) {
  const name = 'performance';
  const entryTypes = ['paint', 'largest-contentful-paint', 'first-input']
  function start() {
    const p = new PerformanceObserver(list => {
      for (const entry of list.getEntries()) {
        report({ name, data: entry });
      }
    })
    p.observe({ entryTypes });
  }
  return { name, start }
}

这里主要通过PerformanceObserver来监听页面渲染的性能数据

JS错误监控

function createJsErrorMonitor(report: ({ name: string, data: any }) => void) {
  const name = "js-error";
  function start() {
    window.addEventListener("error", (e) => {
      // 只有 error 属性不为空的 ErrorEvent 才是一个合法的 js 错误
      if (e.error) {
        report({ name, data: { type: e.type, message: e.message } });
      }
    });
    window.addEventListener("unhandledrejection", (e) => {
      report({ name, data: { type: e.type, reason: e.reason } });
    });
  }
  return { name, start }
}

这里通过监听error事件,然后过滤特定错误,来达到监听全局的js错误

数据上报

封装成sdk

function createSdk(url: string) {
  const monitors: Array<{ name: string, start: Function }> = [];
  const sdk = {
    url,
    report,
    loadMonitor,
    monitors,
    start,
  }
  function report({ name: string, data: any }) {
    // 注意:数据发送前需要先序列化为字符串
    navigator.sendBeacon(url, JSON.stringify({ name: string, data: any }));
  }
  function loadMonitor({ name: string, start: Function }) {
    monitors.push({ name: string, start: Function });
    // 实现链式调用
    return sdk;
  }
  function start() {
    monitors.forEach(m => m.start());
  }
  return sdk;
}

这里的loadMonitor实现了一个链式调用,为了实现加载多个不同的监听函数,确实是个奇妙的用法。

关注请求性能

请求异常除了请求错误外,我们还关注慢请求,你可以参考 Performance Resource Timing 来获取请求各阶段耗时,找出所有慢请求

总结

本次学习了解到了很多关于前端监控的api,总的来说都是原生api,说明进阶一个新的领域还的看自身的基础牢固。