Skip to content
标签
note
字数
787 字
阅读时间
4 分钟

数据埋点其实要考虑的就是 用户行为、错误警告、页面性能 三个核心方面

SDK 核心代码

js
let SDK = null // EasyAgentSDK 实例对象
const QUEUE = [] // 任务队列
const NOOP = (v) => v

// 通过 web-vitals 页面性能指标
const reportWebVitals = (onPerfEntry) => {
  if (onPerfEntry && onPerfEntry instanceof Function) {
    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
      getCLS(onPerfEntry) // 布局偏移量
      getFID(onPerfEntry) // 首次输入延迟时间
      getFCP(onPerfEntry) // 首次内容渲染时间
      getLCP(onPerfEntry) // 首次最大内容渲染时间
      getTTFB(onPerfEntry) // 首个字节到达时间
    })
  }
}

export default class EasyAgentSDK {
  appId = ''
  baseUrl = ''
  timeOnPage = 0
  config = {}
  onPageShow = null
  onPagesHide = null
  
  constructor(options = {}) {
    if (SDK) return

    SDK = this
    this.appId = options.appId
    this.baseUrl = options.baseUrl || window.location.origin
    this.onPageShow = options.onPageShow || NOOP
    this.onPagesHide = options.onPagesHide || NOOP

    // 初始化监听页面变化
    this.listenPage()
  }
  
  // 设置 config
  setConfig(congfig){
    this.config = congfig
  }

  // 刷新任务队列
  flushQueue() {
    Promise.resolve().then(() => {
      QUEUE.forEach((fn) => fn())
      QUEUE.length = 0;
    })
  }

  // 监听页面变化
  listenPage() {
    let pageShowTime = 0

    window.addEventListener('pageshow', () => {
      pageShowTime = performance.now()
      
       // 页面性能指标上报
      reportWebVitals((data) => {
        this.performanceReport({ data })
      })
      
      // 执行 onPageShow
      this.onPageShow();
    })

    window.addEventListener('pagehide', () => {
      // 记录用户在页面停留时间
      this.timeOnPage = performance.now() - pageShowTime
      
      // 刷新队列前执行 onPagesHide
      this.onPagesHide();

      // 刷新任务队列
      this.flushQueue();
    })
  }

  // Json 转 FormData
  json2FormData(data){
    const formData = new FormData()

    Object.keys(data).forEach(key => {
      let value = null;
      if(value instanceof Blob){
        value = data[key];
      }else {
        value = JSON.stringify(data[key]);
      }
      formData.append(key, value);
    });

    return formData
  }

  // 自定义上报类型
  report(config) {
    QUEUE.push(() => {
      const formData = json2FormData({
        ...this.config,
        ...config,
        time: new Date().toLocaleString(),
        appId: this.appId,
        pageUrl: window.location.href,
      });
      navigator.sendBeacon(`${this.baseUrl}${config.url || ''}`, formData)
    })
  }

  // 用户行为上报
  actionReport(config) {
    this.report({
      ...config,
      type: 'action',
    })
  }

  // 网络状况上报
  networkReport(config) {
    this.report({
      ...config,
      type: 'network',
    })
  }

  // 页面性能指标上报
  performanceReport(config) {
    this.report({
      ...config,
      type: 'performance',
    })
  }

  // 错误警告上报
  errorReport(config) {
    this.report({
      ...config,
      type: 'error',
    })
  }
}

上报用户行为

统计 PV 和 UV — 自动触发埋点

关于 PVUV 在上述已经做过介绍了,本质上这两个数据统计都可在一个上报类型为 action 数据发送中获得,主要看监控系统是按照怎样的规则对数据进行分析和统计,这里在 SDK 内部监听了页面的 pageshow / pagehide 两个事件:

  • pageshow 中可以上报与 PV / UV 相关的数据 和 页面性能相关的数据

    js
    window.SDK = new EasyAgentSDK({
        appId: 'application_id',
        baseUrl: '//aegis.example.com/collect',
        onPageShow() {
            window.SDK.actionReport({
                data: {} // 其他必要传递的信息
            })
        }
    });
    
    window.SDK.setConfig({
        userId: UserInfo.userId, // 当前用户 id
        userName: UserInfo.userName, // 当前用户 name
    });
    复制代码
  • pagehide 中主要用于计算用户停留在页面上的时间 timeOnPage 和 刷新任务队列

统计用户点击按钮 — 交互式触发埋点

假设我们希望记录某些按钮的使用次数的数据,可以在 document 上监听 click 事件,目的利用事件冒泡以便于不需要侵入不同按钮的 click 事件,比如:

js
const TargetElementFilter = ['export_btn']

const findTarget = (filters) => {
 return filters.find((filter) => TargetElementFilter.find((v) => filter === v)));
}

document.addEventListener('click', (e) => {
  const { id, className, outerHTML } = e.target
  const isTarget = findTarget([id, className])

  if (isTarget) {
    SDK.actionReport({
      data: {
        id, 
        className,
        outerHTML
      }, // 其他必要传递的信息
    })
  }
})

参考

你只会用前端数据埋点 SDK 吗? - 掘金

贡献者

The avatar of contributor named as jiechen jiechen

页面历史

撰写