第136题 如何设计一个前端统计SDK

  • 前端统计的范围
    • 访问量PV
    • 自定义事件
    • 性能,错误
    // 统计sdk
    
    const PV_URL_SET = new Set()
    
    class MyStatistic {
      constructor(productId) {
        this.productId = productId
    
        // 内部处理
        this.initPerformance() // 性能统计
        this.initError() // 错误监控
      }
    
      // 发送统计数据
      send(url, params = {}) {
        params.productId = productId
    
        const paramArr = []
        for (let key in params) {
          const val = params[key]
          paramArr.push(`${key}=${value}`)
        }
    
        const newUrl = `${url}?${paramArr.join('&')}` // url?a=10&b=20
    
        // 用 <img> 发送:1. 可跨域;2. 兼容性非常好
        const img = document.createElement('img')
        img.src = newUrl // get
      }
    
      // 初始化性能统计
      initPerformance() {
        const url = 'yyy'
        this.send(url, performance.timing) // 给最原始的、完整的结果,原始数据。让服务端加工处理
      }
    
      // 初始化错误监控
      initError() {
        window.addEventListener('error', event => {
          const { error, lineno, colno } = event
          this.error(error, { lineno, colno })
        })
        // Promise 未 catch 住的报错
        window.addEventListener('unhandledrejection', event => {
          this.error(new Error(event.reason), { type: 'unhandledrejection' })
        })
      }
    
      pv() {
        const href = location.href
        if (PV_URL_SET.get(href)) return // 不重复发送 pv
    
        this.event('pv')
    
        PV_URL_SET.add(href)
      }
    
      event(key, val) {
        const url = 'xxx' // 自定义事件统计 server API
        this.send(url, {key, val})
      }
    
      error(err, info = {}) {
        const url = 'zzz'
        const { message, stack } = err
        this.send(url, { message, stack, ...info  })
      }
    }
    
    // const s = new MyStatistic('a1') // 最好在DOMContentLoaded的时候在初始化
    // s.pv() // 用户主动发送 SPA 路由切换 PV
    
    // 用户自行发送自定义事件
    // s.event('vip', 'close')
    
    // 用户处理try catch
    // try {
    // } catch(ex) {
    //     s.error(ex, {})
    // }
    
    // 在vue、react单独监听配置的错误的配置 也可以s.error单独发过去。跟try catch一样的

连环问:sourcemap有何作用,如何配置

js报错,可能会问sourcemap相关问题

  • sourcemap作用
    • JS上线时要压缩、混淆
    • 线上的JS报错信息,将无法识别行、列
    • sourcemap即可解决这个问题
  • webpack通过devtool配置sourcemap
    • evalJSeval(...)中,不生成sourcemap
    • source-map:生成单独的map文件,并在JS最后指定
    • eval-source-mapJSeval(...)中,sourcemap内嵌
    • inline-source-mapsourcemap内嵌到JS中,不是单独文件
    • cheap-source-mapsourcemap中只有行信息,没有列
    • eval-cheap-source-mapJSeval(...)中,没有独立的sourcemap文件,cheap-source-map只有行没有列
    • 总结
      • 开发环境使用eval效率高:evaleval-source-mapeval-cheap-source-map
      • 线上环境使用:source-map 生成单独的map文件(不要泄露sourcemap文件)

Last Updated:
Contributors: leeguooooo