当前位置: 首页 > Web前端 > HTML5

如何优雅的处理前端异常?

时间:2023-04-05 15:05:06 HTML5

前端一直是离用户最近的一层。随着产品的完善,我们会更加注重用户体验,但是前端异常却一直萦绕在喉咙里,非常烦人。1、为什么要处理异常?异常是不可控的,会影响最终的渲染,但是我们有充分的理由去做这样的事情。1.提升用户体验;2、远程定位问题;3、未雨绸缪,早发现问题;4、无法重连,尤其是移动端、机型、系统;5、完善的前端解决方案和前端监控系统;对于JS,我们只面临异常。异常的发生不会直接导致JS引擎崩溃,最多是终止当前正在执行的任务。2、需要处理哪些异常?对于前端,我们可以做很多的异常捕获。总结一下,大致有以下几种:JS语法错误、代码异常、AJAX请求异常、静态资源加载异常、Promise异常、iframe异常、跨域异常、脚本错误、崩溃卡顿。接下来,我将针对每种特定情况解释如何处理这些异常。3、对Try-Catch的误解try-catch只能捕获同步运行时错误,对于捕获语法错误和异步错误是无能为力的。1.同步运行时错误:输出:2.我们无法捕获语法错误。让我们修改代码并删除单引号:输出:但是,在我们的开发阶段可以看到语法错误。应该是不能顺利上线环境吧。3、异步错误:可以看日志:没有捕获到异常,这个是我们需要特别注意的。4、window.onerror不是万能的当JS运行时错误发生时,window会触发ErrorEvent接口的error事件,执行window.onerror()。首先尝试同步运行时错误如您所见,我们捕获了一个异常:语法错误呢?控制台打印出这样一个异常:Didn'tcatchthesyntaxerror?怀着忐忑的心情,我们终于尝试了异步运行时错误:控制台输出:接下来我们尝试异常网络请求:我们发现无论是静态资源异常还是接口异常,都抓不到错误。再补充一点:只有当window.onerror函数返回true时,才不会向上抛出异常,否则即使知道异常,控制台还是会显示UncaughtError:xxxxx,控制台不会再出现这样的错误注意:最好在所有JS脚本前面都写onerror,否则可能抓不到错误;onerror无法捕获语法错误;到这里基本就清楚了:在实际使用中,onerror主要来自Catchingunexpectederrors,而try-catch用于监控可预见情况下的特定错误,两者结合使用效率更高。问题又来了,静态资源加载异常抓不到怎么办?1.window.addEventListener当资源(如图片或脚本)加载失败时,加载资源的元素会触发Event接口的错误事件,并对该元素执行onerror()处理函数。这些错误事件不会冒泡到window,但(至少在Firefox中)可以被单个window.addEventListener捕获。控制台输出:因为异常的网络请求不会引起事件冒泡,所以一定要在capture阶段进行捕获。但是这种方法虽然可以捕捉到异常的网络请求,但是无法判断HTTP的状态是404还是500等,所以需要配合服务器日志进行排查分析。注意:不同浏览器返回的错误对象可能不同,需要注意兼容处理。需要注意避免addEventListener重复监听。2.PromiseCatch在promise中使用catch可以轻松捕获异步错误,非常简单。没有catch的Promise抛出的错误是无法被onerror或try-catch捕获的,所以我们一定不要忘记写catch来处理Promise中抛出的异常。解决方案:为了防止遗漏Promise异常,建议全局添加unhandledrejection监控器,全局监控UncaughtPromiseError。使用方法:让我们继续尝试:如果没有抓到Promise怎么办?好吧,原来它也会被正常捕获。所以我们上面说了,为了防止遗漏Promise异常,建议全局添加一个unhandledrejection的监控器,全局监控UncaughtPromiseError。再补充一点:如果去掉控制台的异常显示,还需要添加:三、VUEerrorHandler四、React异常捕获React16提供了一个内置函数componentDidCatch,使用它可以方便的获取下面的错误信息UI的某一部分引起的reactJS错误不应该破坏整个程序。为了帮助React用户解决这个问题,React16引入了一个关于错误边界的新概念。需要注意的是:错误边界不会捕获下面的错误。1.事件处理程序2.异步代码3.服务端渲染代码4.错误边界区的错误举个小例子,下面componentDIdCatch(error,info)中的类会成为错误边界:那么我们像普通组件一样使用它:componentDidCatch()方法的工作方式类似于JS的catch{}模块,但是对于组件来说,只有类类型的组件(类组件)可以作为错误边界。事实上,大多数时候我们可以在整个程序中定义一个错误边界组件并永远使用它!5.iframe异常对于iframe的异常捕获,我们不得不使用window.onerror:一个简单的例子可能如下:6.Scripterror一般情况下,如果出现Scripterror之类的错误,基本可以确定是存在跨域问题。这时候其他的辅助信息就不会太多了,解决方法无外乎如下:跨域资源共享机制(CORS):我们在script标签中加入crossOrigin属性。或者动态添加js脚本:特别注意,服务器需要设置:Access-Control-Allow-Origin另外,我们也可以试试这个——另一种解决脚本错误的方法:简要说明:重写了的addEventListener方法事件目标;包装传入的侦听器,返回包装后的侦听器,并尝试捕获其执行;浏览器不会拦截跨域try-catch捕获到的异常,所以当catch到来时,是有栈信息的;再次抛出异常时,执行相同的域代码,因此捕获window.onerror时不会丢失堆栈信息;通过包裹addEventListener,我们还可以达到“扩展堆栈”的效果:七、Crash和freeze是指网页暂时响应变慢,JS可能没有及时执行。但崩溃是不同的。网页崩溃,JS没有运行。有什么办法可以监控网页崩溃并报告网页崩溃?崩溃和死机也不容忽视,可能会导致您的用户流失。利用window对象的load和beforeunload事件实现对网页崩溃的监控。基于以下原因,我们可以使用ServiceWorker来监控网页崩溃:ServiceWorker有自己独立的工作线程,与网页不同。如果网页崩溃,一般情况下ServiceWorker不会崩溃;ServiceWorker生命周期一般比网页长,可以用来监控网页的状态;网页可以通过navigator.serviceWorker.controller.postMessageAPI向自己负责的SW发送消息。八、报错1、通过ajax发送数据:由于ajax请求本身可能会出现异常,可能会导致跨域问题,所以一般建议以动态创建img标签的形式报错。2.动态创建img标签的形式:收集到太多异常信息,怎么办?在实践中,我们不得不考虑这样一种情况:如果你的网站访问量很大,必然会出现很多错误发送的消息。这时候我们就需要设置采集速率来降低服务器的压力:采集速率要根据实际情况设置。随机数或某些用户特征都是不错的选择。九。总结回到我们一开始提出的问题,如何优雅地处理异常?1.增加可疑区域的Try-Catch2。全局监听JS异常window.onerror3。全局监听静态资源异常window.addEventListener4。捕获Promise异常而不捕获:unhandledrejection5.VUEerrorHandler和ReactcomponentDidCatch6。监控网页崩溃:加载和卸载之前的窗口对象7。跨域crossOrigin的解决方法其实很简单。采用组合方案,按类型捕获异常,这样基本上80%-90%的问题是看不见的。喜欢我的文章可以关注我哦~