数据埋点
keywords:错误 收集 监控
https://www.bilibili.com/video/BV1td4y1N7jg
请求
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
// 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);优雅降级
/**
* 向下兼容发送信号的方法
*/
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指令触发

addEventListener('click')

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


用户可视埋点-intersectionObserver
替换Element.getBoundingClientRect + scroll方案
商品出现在用户眼前,即曝光,即可进行埋点
错误收集方式
https://segmentfault.com/a/1190000015187025
https://juejin.cn/post/6844903709323837454
try{}catch(){}
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事件
window.onerror = function (message, url, line) {
alert(message);
return false;
}通过返回false,这个函数实际就充当了整个文档的try-catch语句,可以捕获所有无代码处理的运行错误.但是浏览器在使用这个事件处理错误的方式有明显不同,在IE中,即使发生onerror事件,代码仍然会正常执行,所有变量和数据都将得到保留,因此能在onerror事件处理程序中访问它们,但在firefox中,常规代码会停止执行,事件发生之前的所有变量和数据都将被销毁,因此几乎就无法判断错误了,且另外window.onerror事件不能捕获promise的异常错误信息. 所以我在这里使用的是try...catch...,但是我觉得具体的使用方法可以根据自己的业务需求来确定,我这里只是做一个示例,实际的实现途径还有很多,但是万法同宗.
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则可以拿到错误
window.addEventListener('error', (errorEvent) => {
console.log(errorEvent)
cosnole.log(errorEvent.message)
}, true)promise错误收集
https://juejin.cn/post/6844903502435581959
三种情况触发catch
一、bug
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主动抛出
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三、嵌套
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
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 failedunhandledrejection
在前文中提到Promise中的错误并不能被try...catch和window.onerror捕获。这时候我们就需要unhandledrejection来帮我们捕获这部分错误。
window.addEventListener('unhandledrejection', (e) => {
console.log(`Promise.reject()中的内容,告诉你发生错误的原因:${e.reason}`);
console.log(`Promise对象 :${e.promise}`);
});
Vue错误收集
errorHandler
https://v2.cn.vuejs.org/v2/api/#errorHandler
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 都通过此选项提供了官方支持。
示例
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
app.config.errorHandler = (err, instance, info) => {
// handle error, e.g. report to a service
}
xxxsjan Docs