2022-11-29【监控】前端性能监控

onerror

window.onerror是一个全局变量,默认值为null。当有js运行时错误触发时,window会触发error事件,并执行window.onerror()。onerror可以接受多个参数。

window.onerror = function(message, source, lineno, colno, error) { ... }

函数参数

*   message错误信息字符串)。可用于HTML onerror=""处理程序中的event
*   source发生错误的脚本URL字符串
*   lineno发生错误的行号数字
*   colno发生错误的列号数字
*   errorError对象

若该函数返回true则阻止执行默认事件处理函数如异常信息不会在console中打印没有返回值或者返回值为false的时候异常信息会在console中打印

addEventListener(‘error’)

监听js运行时错误事件,会比window.onerror先触发,与onerror的功能大体类似,不过事件回调函数传参只有一个保存所有错误信息的参数,不能阻止默认事件处理函数的执行,但可以全局捕获资源加载异常的错误

window.onerror = function (message, source, lineno, colno, error) {
  console.warn('onerror============ %s', error);
  return true;
};
window.addEventListener('error', function (event) {
  console.warn('onerror============ %s', event);
  return true;
});

vue 异常 钩子

Vue.config.errorHandler = function (err, vm, info) {
  console.log(`Error: ${err.toString()}\nInfo: ${info}`);
  aegis.error(`Error: ${err.toString()}\nInfo: ${info}`);
};

vue 路由 异常钩子

router.onError((error) => {
  const jsPattern = /Loading chunk (\S)+ failed/g;
  const cssPattern = /Loading CSS chunk (\S)+ failed/g;
  const isChunkLoadFailed = error.message.match(jsPattern || cssPattern);
  const targetPath = router.history.pending.fullPath;
  if (isChunkLoadFailed) {
    localStorage.setItem('targetPath', targetPath);
    window.location.reload();
  }
});
  • 如果想通过onerror函数收集不同域的js错误,我们需要做两件事:
  1. 相关的js文件上加上Access-Control-Allow-Origin:*的response header
  2. 引用相关的js文件时加上crossorigin属性
    <script type="text/javascript" src="http://b.com/b.js"  crossorigin></script>
    

异常上报工具

系统发版,用户跳转页面 404问题

通过 window.addEventListener 监听资源加载报错

// index.html head顶部
 window.addEventListener('error', (e) => {
        // 防止刷新过后资源依然404导致页面无限刷新, 在router.afterEach里删除
        if (sessionStorage.staticReload) {
            return
        }
        let localName = e.target.localName
        if (localName === 'script' || localName === 'link') {
        // 只刷新一次 用 staticReload 标记一下
            window.sessionStorage.setItem('staticReload', '1')
            // reload里一定要加 true
            window.location.reload(true);
        }
        // 这个true一定要加,否则监听不到
    }, true)


// 或
window.addEventListener('error', function (event) {
    try {
        const target = event.target || event.srcElement;
        if (
            target instanceof HTMLElement &&
            ['LINK', 'SCRIPT', 'IMG'].indexOf(target.nodeName) !== -1
        ) {
            // 下载资源失败
            // @ts-ignore
            const src = target.src || target.href;
            if (window.location.href.indexOf(src) !== 0) {
                reportResourceFail({
                    detail: src
                });
            }
        }
    } catch (err) {
    }
}, true);
// router.js
// 跳转成功,说明css js资源加载成功,则去掉 staticReload 标记
router.afterEach(() => {
    sessionStorage.removeItem('staticReload')
})

```

注意点

  1. window.addEventListener 的第三个参数 一定要是 true,表示用事件捕获。
  2. window.location.reload(true) 里一定要用 true, 表示直接从服务器取资源。
  3. 加一个标记,只刷新一次就够了,因为如果是因为某个资源本身不存在导致刷新完又404,会让页面无限刷新。我们解决的只是能保证刷新页面就能获取到的正常打包资源。

###结语 这样一旦用户停留页面的时间正好跨越了发版时间,资源加载404的情况下,会直接在当前页面强行刷新一下,然后就能正常使用了。