You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
window.addEventListener('load',function(){// 进页面,首先检测上次是否崩溃if(sessionStorage.getItem('good_exit')&&sessionStorage.getItem('good_exit')!=='true'){/* insert crash logging code here */console.log('Hey, welcome back from your crash, looks like you crashed on: '+sessionStorage.getItem('time_before_crash'));}sessionStorage.setItem('good_exit','pending');setInterval(function(){sessionStorage.setItem('time_before_crash',newDate().toString());},1000);});window.addEventListener('beforeunload',function(){// 离开页面前,重置标志位sessionStorage.setItem('good_exit','true');});
前端监控体系怎么搭建?
背景
前端一直是距离用户最近的一层,随着产品的日益完善,我们会更加注重用户体验,而前端异常特别是外网客户异常,一直是前端开发的痛点。最近在家办公,对公司的监控系统,又做了一遍复习,特作此记录。
异常是不可控的,会影响最终的呈现结果,所以任何一个成熟的前端团队,都有充分的理由去做这样的事情:
1.成熟的工程化,前端监控系统必不可少;
2.远程定位问题,对于对外web页面,让客户配合找bug是一件及其不职业且低效的事情;
3.错误预警上报,及早发现并修复问题;
4.问题复现,尤其是移动端,机型,系统都是问题;
对于
JS
而言,我们面对的仅仅只是异常,异常的出现不会直接导致JS
引擎崩溃,最多只会使当前执行的任务终止。需要处理哪些异常?
对于前端来说,我们可做的异常捕获还真不少。总结一下,大概如下:
JS
语法错误、代码运行异常Http
请求异常Promise
异常Iframe
异常Script error
下面针对每种具体情况来说明如何处理这些异常。
点兵点将
一、Try-Catch 错误捕获
try-catch
只能捕获到同步的运行时错误,对语法和异步错误却无能为力。1.同步运行时错误:
输出:错误捕获: ReferenceError: ver is not defined
at :3:14
2.不能捕获到语法错误,我们修改一下代码,删掉一个单引号:
以上两种包括多种语法错误,在我们开发阶段基本Eslint就会捕获到,在线上环境出现的可能性比较小,如果是,那就是前端工程化基础不好。
3.异步错误
二、window.onerror 信息全面,但不是万能的
当
JS
运行时错误发生时,window
会触发一个ErrorEvent
接口的error
事件,并执行window.onerror()
。1.首先试试同步运行时错误
可以看到,我们捕获到了异常:
2.来试试异步运行时错误:
控制台输出了:
3.接着,我们试试网络请求异常的情况:
我们发现,不论是静态资源异常,或者接口异常,错误都无法捕获到。
在实际的使用过程中,
onerror
主要是来捕获预料之外的错误,而try-catch
则是用来在可预见情况下监控特定的错误,两者结合使用更加高效。问题又来了,捕获不到静态资源加载异常怎么办?
三、window.addEventListener 静态资源加载错误
当一项资源(如图片或脚本)加载失败,加载资源的元素会触发一个
Event
接口的error
事件,并执行该元素上的onerror()
处理函数。这些error
事件不会向上冒泡到window
,但可以被window.addEventListener error
监听捕获。控制台输出:
由于网络请求异常不会事件冒泡,因此必须在捕获阶段将其捕捉到才行,但是这种方式虽然可以捕捉到网络请求的异常,但是无法判断
HTTP
的状态是404
还是其他比如500
等等,所以还需要配合服务端日志才进行排查分析才可以。需要注意:
error
对象可能不同,需要注意兼容处理。addEventListener
重复监听。四、Promise Catch
在
promise
中使用catch
可以非常方便的捕获到异步error
,这个很简单。没有写
catch
的Promise
中抛出的错误无法被onerror
或try-catch
捕获到,所以我们务必要在Promise
中不要忘记写catch
处理抛出的异常。解决方案: 为了防止有漏掉的
Promise
异常,建议在全局增加一个对unhandledrejection
来全局监听Uncaught Promise Error
:测试列子: 见actionTest/index.js
可以看到如下输出:
提醒一句:与onError 采用return true来结束控制器的默认错误打印,unhandledrejection如果去掉控制台的异常显示,需要加上:
虽然可以使用增加
unhandledrejection
的监听来捕获promise的异常处理,但处理fetch
或者ajax
的异常捕获,还是不太适合,因为他只能捕获到这个错误,而无法获取错误出现的位置和错误详情;五、Http请求错误
在使用
ajax
或者fetch
请求数据时, 这里主要说Fetch, 以上说过unhandledrejection能捕获到请求的异常,但没法获取到请求的详情,哪个url 发起,传参是什么,一无所知。所有这里最好的方式就是重写fetch,具体操作:还是上面的测试列子: 见actionTest/index.js
可以看到如下输出:
六、React 框架异常捕获
在日常开发中,web开发基本都是基于React和Vue这种成熟的UI框架来做,因为工作里只用到了
React
,所以这里不涉及Vue
。 16提供了两个钩子componentDidCatch
与getDerivedStateFromError
,详情见官方文档, 使用他们可以非常简单的获取到react
下的错误信息;详细见代码src/index.js
需要注意的是:
Error boundaries
并不会捕捉下面这些错误。1.事件处理器
2.异步代码
3.服务端的渲染代码
4.在
error boundaries
区域内的错误实际使用中,我们只在根组件去可以定义一个
error boundary
组件,然后整个UI的错误都通过这里上报!像Dva这种框架,也在最外层提供了上报入口。七、Script error
一般情况,如果出现
Script error
这样的错误,基本上可以确定是出现了跨域问题。这时候,是不会有其他太多辅助信息的,但是解决思路无非如下:跨源资源共享机制(
CORS
):我们为script
标签添加crossOrigin
属性。特别注意,服务器端需要设置:Access-Control-Allow-Origin
此外,我们也可以试试这个-解决 Script Error 的另类思路:
简单解释一下:
EventTarget
的addEventListener
方法;listener
进行包装,返回包装过的listener
,对其执行进行try-catch
;try-catch
起来的异常进行跨域拦截,所以catch
到的时候,是有堆栈信息的;throw
出来异常的时候,执行的是同域代码,所以window.onerror
捕获的时候不会丢失堆栈信息;利用包装
addEventListener
,我们还可以达到「扩展堆栈」的效果:八、iframe 异常
对于
iframe
的异常捕获,可以通过window.onerror
来实现,一个简单的例子可能如下:现在iframe在前端中应用比较少,这里不再展开
九、崩溃和卡顿
卡顿也就是网页暂时响应比较慢,通常我们说的60fps, 就是描述这个的,卡顿的现象就是造成
JS
无法及时执行。但崩溃就不一样了,崩溃直接造成JS
不运行了,JS执行进程卡死,相比网页崩溃上报更难?崩溃和卡顿都是不可忽视的,都会导致用户体验不好,而加剧用户流失。1、卡顿的实现相对比较简单,我们可以通过requestAnimationFrame采集样本,来判断页面是否长期(几秒内)低于30fps或其他阈值。
看下面具体实现:
2、崩溃的监控相对于稍显复杂来说,在这篇文章讲的很清楚:网页崩溃的监控:
这个方案有两个问题:
Service Worker
有自己独立的工作线程,与网页区分开,网页崩溃了,Service Worker
一般情况下不会崩溃;Service Worker
生命周期一般要比网页还要长,可以用来监控网页的状态;navigator.serviceWorker.controller.postMessage API
向掌管自己的SW
发送消息。SW中注册
;并每隔1s或几秒向SW汇报
一下,SW收到消息后更新这个页面的最后更新时间;SW自己,每隔几秒(大于前面的时间)扫描
自己注册页面的更新时间,如果某个页面最后更新时间是大于N秒,则可以判断为崩溃;JS实现:
总结
以上基本涵盖了监控系统中90%以上的错误捕获案例,但这只是监控系统的开端,只能算是Demo级别的代码。市面上有很多成熟的监控库可参考,比如FunderBug,Raven-Js等,我们团队的监控库就是是在Raven上做了一层扩展,然后结合IndexDb和压缩库(pako),以及服务端日志收集采用Koa来实现,知识点很多,但前面这些非常重要。
参考
前端代码异常监控实战
如何优雅处理前端异常?
Error Boundaries
前端监控知识点
Capture and report JavaScript errors with window.onerror
The text was updated successfully, but these errors were encountered: