Skip to content
On this page

数据埋点

keywords:错误 收集 监控

https://www.bilibili.com/video/BV1td4y1N7jg

请求

typescript
let img = new Image()
img.onload = img.onerror = img.onabort = function(){
  img = img.onload = img.onerror = img.onabort = null
}
img.src = "http://xxx.xxx.com/tracker.gif?aa=aa&bbb=bbb"

sendBeacon

https://www.jianshu.com/p/04e88271a8f2?from

post请求,传参 json、blob、formData

typescript
// json 自动设置text/plain
navigator.sendBeacon(url, jsonData);
// blob
const blob = new Blob([JSON.stringify(data), {
  type: 'application/x-www-form-urlencoded',
}]);
navigator.sendBeacon(url, blob);
// formData
navigator.sendBeacon(url, formData);

优雅降级

typescript
/**
 * 向下兼容发送信号的方法
 */
const sendBeacon = navigator.sendBeacon
  ? (url, data) => {
    if (data) navigator.sendBeacon(url, JSON.stringify(data));
  }
  : (url, data) => {
    // 传统方式传递参数
    const beacon = new Image();
    beacon.src = `${url}?v=${encodeURIComponent(JSON.stringify(data))}`;
  };

埋点类型

按钮

可以通过vue指令触发

img

addEventListener('click')

img

路由

可以通过beforeEach计算to,from,维护一个时间戳,新旧对比计算

img

img

用户可视埋点-intersectionObserver

替换Element.getBoundingClientRect + scroll方案

商品出现在用户眼前,即曝光,即可进行埋点

错误收集方式

https://segmentfault.com/a/1190000015187025

https://juejin.cn/post/6844903709323837454

try{}catch(){}

typescript
try {
    // some code
  } catch (err) {
    console.error(err)
  }


console.error = (func => {
  return (...args) => {
    // 在这里就可以收集到console.error的错误
    // 做一些事情
    func.apply(console, args);
  }
})(console.error);

window.onerror

任何没有通过try-catch处理的错误都会触发window对象的error事件,在任何web浏览器中,onerror事件处理程序都不会创建event对象,但它可以接收三个参数: 错误信息,错误所在的URL和行号.多数情况下,只有错误信息有用,因为URL只给出了文档的位置,而行号所指的代码既可能出自内部JavaScript代码,也可能出自外部文件. 只要发生错误,无论是不是浏览器生成的,都会触发error事件

css
window.onerror = function (message, url, line) {
    alert(message);
    return false;
}

通过返回false,这个函数实际就充当了整个文档的try-catch语句,可以捕获所有无代码处理的运行错误.但是浏览器在使用这个事件处理错误的方式有明显不同,在IE中,即使发生onerror事件,代码仍然会正常执行,所有变量和数据都将得到保留,因此能在onerror事件处理程序中访问它们,但在firefox中,常规代码会停止执行,事件发生之前的所有变量和数据都将被销毁,因此几乎就无法判断错误了,且另外window.onerror事件不能捕获promise的异常错误信息. 所以我在这里使用的是try...catch...,但是我觉得具体的使用方法可以根据自己的业务需求来确定,我这里只是做一个示例,实际的实现途径还有很多,但是万法同宗.

typescript
window.onerror = (msg, url, lineNum, colNum, err) => {
  console.log(`错误发生的异常信息(字符串):${msg}`)
  console.log(`错误发生的脚本URL(字符串):${url}`)
  console.log(`错误发生的行号(数字):${lineNum}`)
  console.log(`错误发生的列号(数字):${colNum}`)
  console.log(`错误发生的Error对象(错误对象):${err}`)
};

addEventListener('error')

window.onerror是拿不到资源加载错误的,而addEventListener则可以拿到错误

typescript
window.addEventListener('error', (errorEvent) => {
    console.log(errorEvent)
    cosnole.log(errorEvent.message)
}, true)

promise错误收集

https://juejin.cn/post/6844903502435581959

三种情况触发catch
一、bug
css
function asyncTask(url) {
  return new Promise((resolve, reject) => {
    a.push(1);

    if (url) {
      return setTimeout(() => {
        resolve({
          id: 1
        });
      }, 500);
    }

    reject({
      error: 'url missing in async task 1'
    });
  });
}

asyncTask('google.com').catch(err => console.log(err)); //ReferenceError: a is not defined
二、throw主动抛出
css
function asyncTask(url) {
  return new Promise((resolve, reject) => {
    if (url) {
      throw new Error('terminate now');
      return setTimeout(() => {
        resolve({
          id: 1
        });
      }, 500);
    }

    reject({
      error: 'url missing in async task 1'
    });
  });
}

asyncTask('google.com').catch(err => console.log(err)); //Error: terminate now
三、嵌套
typescript
function asyncTask(url) {
  return new Promise((resolve, reject) => {
    if (url) {
      return setTimeout(() => {
        resolve(asyncTask2());// <----嵌套
      }, 500);
    }
    reject({error: 'url missing in async task 1'});
  });
}

function asyncTask2(url) {
  return new Promise((resolve, reject) => {
    if (url) {
      return resolve({
        id:2
      });
    }
    reject({error: 'url missing in async task 2'});
  });
}

asyncTask('google.com')
  .catch(err => {
    console.log('failed ', err); // { error: 'url missing in async task 2' }
    return err;
  });
catch 监控哪些then
css
asyncTask()
  .then()
  .then()
  .then()
  .catch() // 覆盖 asyncTask 和3个 then


asyncTask()
  .catch() // 只覆盖 asyncTask
  .then()
  .then()
  .catch() // 覆盖了2个 then


需要注意的就是,和 then 一样, catch 也会返回一个可链式操作的新 promise 对象。
在 catch 中抛出的错误会被下一个 catch 捕获
asyncTask()
  .then()
  .then()
  .catch(err => {throw new Error('operation failed')})
  .catch(err => console.log(err)) // operation failed
unhandledrejection

在前文中提到Promise中的错误并不能被try...catch和window.onerror捕获。这时候我们就需要unhandledrejection来帮我们捕获这部分错误。

typescript
window.addEventListener('unhandledrejection', (e) => {
  console.log(`Promise.reject()中的内容,告诉你发生错误的原因:${e.reason}`);
  console.log(`Promise对象 :${e.promise}`);
});

img

Vue错误收集

errorHandler

https://v2.cn.vuejs.org/v2/api/#errorHandler

typescript
Vue.config.errorHandler = function (err, vm, info) {
  //`err`是js错误栈信息,可以获取到具体的js报错位置。
  //`vm` vue实例
  //`info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
}

指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例。

从 2.2.0 起,这个钩子也会捕获组件生命周期钩子里的错误。同样的,当这个钩子是 undefined 时,被捕获的错误会通过 console.error 输出而避免应用崩溃。

从 2.4.0 起,这个钩子也会捕获 Vue 自定义事件处理函数内部的错误了。

从 2.6.0 起,这个钩子也会捕获 v-on DOM 监听器内部抛出的错误。另外,如果任何被覆盖的钩子或处理函数返回一个 Promise 链 (例如 async 函数),则来自其 Promise 链的错误也会被处理。

错误追踪服务 Sentry Bugsnag 都通过此选项提供了官方支持。

示例

typescript
function formatComponentName(vm) {
    if (vm.$root === vm) return 'root';
    var name = vm._isVue
        ? (vm.$options && vm.$options.name) ||
        (vm.$options && vm.$options._componentTag)
        : vm.name;
    return (
        (name ? 'component <' + name + '>' : 'anonymous component') +
        (vm._isVue && vm.$options && vm.$options.__file
            ? ' at ' + (vm.$options && vm.$options.__file)
            : '')
    );
}
Vue.config.errorHandler = function(err, vm, info) {
    if (vm) {
        var componentName = formatComponentName(vm);
        //调用错误日志收集接口
    } else {
        //调用错误日志收集接口
    }
};

vue3 https://vuejs.org/api/application.html#app-config-errorhandler

typescript
app.config.errorHandler = (err, instance, info) => {
  // handle error, e.g. report to a service
}

粤ICP备2024285819号