onerror
window.onerror 是一个全局变量,默认值为 null。当有 js 运行时错误触发时,window 会触发 error 事件,并执行 window.onerror()。onerror 可以接受多个参数。
1 2 3 4 5 6 7 8 9 10 11
| window.onerror = function(message, source, lineno, colno, error) { ... }
函数参数:
* message:错误信息(字符串)。可用于HTML onerror=""处理程序中的event。 * source:发生错误的脚本URL(字符串) * lineno:发生错误的行号(数字) * colno:发生错误的列号(数字) * error:Error对象
若该函数返回true,则阻止执行默认事件处理函数,如异常信息不会在console中打印。没有返回值或者返回值为false的时候,异常信息会在console中打印
|
addEventListener(‘error’)
监听 js 运行时错误事件,会比 window.onerror 先触发,与 onerror 的功能大体类似,不过事件回调函数传参只有一个保存所有错误信息的参数,不能阻止默认事件处理函数的执行,但可以全局捕获资源加载异常的错误
1 2 3 4 5 6 7 8
| 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 异常 钩子
1 2 3 4
| Vue.config.errorHandler = function (err, vm, info) { console.log(`Error: ${err.toString()}\nInfo: ${info}`); aegis.error(`Error: ${err.toString()}\nInfo: ${info}`); };
|
vue 路由 异常钩子
1 2 3 4 5 6 7 8 9 10
| 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 错误,我们需要做两件事:
- 相关的 js 文件上加上 Access-Control-Allow-Origin:*的 response header
- 引用相关的 js 文件时加上 crossorigin 属性
1
| <script type="text/javascript" src="http://b.com/b.js" crossorigin></script>
|
异常上报工具
系统发版,用户跳转页面 404 问题
通过 window.addEventListener 监听资源加载报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| window.addEventListener( "error", (e) => { if (sessionStorage.staticReload) { return; } let localName = e.target.localName; if (localName === "script" || localName === "link") { window.sessionStorage.setItem("staticReload", "1"); window.location.reload(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 ) { const src = target.src || target.href; if (window.location.href.indexOf(src) !== 0) { reportResourceFail({ detail: src, }); } } } catch (err) {} }, true );
|
1 2 3 4 5
|
router.afterEach(() => { sessionStorage.removeItem("staticReload"); });
|
注意点
- window.addEventListener 的第三个参数 一定要是 true,表示用事件捕获。
- window.location.reload(true) 里一定要用 true, 表示直接从服务器取资源。
- 加一个标记,只刷新一次就够了,因为如果是因为某个资源本身不存在导致刷新完又 404,会让页面无限刷新。我们解决的只是能保证刷新页面就能获取到的正常打包资源。
结语
这样一旦用户停留页面的时间正好跨越了发版时间,资源加载 404 的情况下,会直接在当前页面强行刷新一下,然后就能正常使用了。