欢迎进入教育资讯网!
当前页面: 首页 > 电脑IT培训 > Web前端 > 如何处理前端异常问题?这篇值得你一看!

如何处理前端异常问题?这篇值得你一看!

来源:教育资讯网 80 2021-07-27

  ***小编要跟大家分享的文章是关于Web前端工程师该如何处理前端异常问题?前端一直是距离用户**近的一层,随着产品的日益完善,我们会更加注重用户体验。前端异常也是需要引起前端工程师重点关注的问题,那么当出现异常时该如何处理呢?下面就来和小编一起看一看本篇文章吧~

  一、为什么要处理异常

  异常是不可控的,会影响**终的呈现结果,但是我们有充分的理由去做这样的事情。

  1.增强用户体验;

  2.远程定位问题;

  3.未雨绸缪,及早发现问题;

  4.无法复线问题,尤其是移动端,机型,系统都是问题;

  5.完善的前端方案,前端监控系统;

  对于JS而言,我们面对的**只是异常,异常的出现不会直接导致JS引擎崩溃,**多只会使当前执行的任务终止。

  二、需要处理哪些异常?

  对于前端来说,我们可做的异常捕获还真不少。总结一下,大概如下:

  ·JS语法错误、代码异常

  ·AJAX请求异常

  ·静态资源加载异常

  ·Promise异常

  ·Iframe异常

  ·跨域Scripterror

  ·崩溃和卡顿

  下面我会针对每种具体情况来说明如何处理这些异常。

  三、Try-Catch的误区

  try-catch只能捕获到同步的运行时错误,对语法和异步错误却无能为力,捕获不到。

  1.同步运行时错误:

  try{

  letname='jartto';

  console.log(nam);

  }catch(e){

  console.log('捕获到异常:',e);

  }

  输出:

  捕获到异常:ReferenceError:namisnotdefined

  at:3:15

  2.不能捕获到语法错误,我们修改一下代码,删掉一个单引号:

  try{

  letname='jartto;

  console.log(nam);

  }catch(e){

  console.log('捕获到异常:',e);

  }

  输出:

  UncaughtSyntaxError:Invalidorunexpectedtoken

  不过语法错误在我们开发阶段就可以看到,应该不会顺利上到线上环境。

  3.异步错误

  try{

  setTimeout(()=>{

  undefined.map(v=>v);

  },1000)

  }catch(e){

  console.log('捕获到异常:',e);

  }

  我们看看日志:

  UncaughtTypeError:Cannotreadproperty'map'ofundefined

  atsetTimeout(:3:11)

  并没有捕获到异常,这是需要我们特别注意的地方。

  四、window.onerror不是***的

  当JS运行时错误发生时,window会触发一个ErrorEvent接口的error事件,并执行

  window.onerror()。

  /**

  *@param{String}message错误信息

  *@param{String}source出错文件

  *@param{Number}lineno行号

  *@param{Number}colno列号

  *@param{Object}errorError对象(对象)

  */

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

  console.log('捕获到异常:',{message,source,lineno,colno,error});

  }

  1.首先试试同步运行时错误

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

  //message:错误信息(字符串)。

  //source:发生错误的脚本URL(字符串)

  //lineno:发生错误的行号(数字)

  //colno:发生错误的列号(数字)

  //error:Error对象(对象)

  console.log('捕获到异常:',{message,source,lineno,colno,error});

  }

  Jartto;

  可以看到,我们捕获到了异常:

  2.再试试语法错误呢?

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

  console.log('捕获到异常:',{message,source,lineno,colno,error});

  }

  letname='Jartto

  控制台打印出了这样的异常:

  UncaughtSyntaxError:Invalidorunexpectedtoken

  什么,竟然没有捕获到语法错误?

  3.怀着忐忑的心,我们***来试试异步运行时错误:

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

  console.log('捕获到异常:',{message,source,lineno,colno,error});

  }

  setTimeout(()=>{

  Jartto;

  });

  控制台输出了:

  捕获到异常:{message:""UncaughtReferenceError:Jarttoisnotdefined"",source:""http://127.0.0.1:8001/"",lineno:36,colno:5,error:ReferenceError:Jarttoisnotdefined

  atsetTimeout(http://127.0.0.1:8001/:36:5)}

  4.接着,我们试试网络请求异常的情况:

  

  

  我们发现,不论是静态资源异常,或者接口异常,错误都无法捕获到。

  补充一点:window.onerror函数只有在返回true的时候,异常才不会向上抛出,否则即使是知道异常的发生控制台还是会显示

  UncaughtError:xxxxx

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

  console.log('捕获到异常:',{message,source,lineno,colno,error});

  returntrue;

  }

  setTimeout(()=>{

  Jartto;

  });

  控制台就不会再有这样的错误了:

  UncaughtReferenceError:Jarttoisnotdefined

  atsetTimeout((index):36)

  需要注意:onerror比较好写在所有JS脚本的前面,否则有可能捕获不到错误;onerror无法捕获语法错误;

  到这里基本就清晰了:在实际的使用过程中,onerror主要是来捕获预料之外的错误,而try-catch

  则是用来在可预见情况下监控特定的错误,两者结合使用更加高效。

  问题又来了,捕获不到静态资源加载异常怎么办?

  五、window.addEventListener

  当一项资源(如图片或脚本)加载失败,加载资源的元素会触发一个Event接口的error事件,并执行该元素上的onerror()处理函数。这些

  error事件不会向上冒泡到window,不过(至少在Firefox中)能被单一的window.addEventListener捕获。

  

  window.addEventListener('error',(error)=>{

  console.log('捕获到异常:',error);

  },true)

  

  

  控制台输出:

  由于网络请求异常不会事件冒泡,因此必须在捕获阶段将其捕捉到才行,但是这种方式虽然可以捕捉到网络请求的异常,但是无法判断HTTP的状态是404

  还是其他比如500等等,所以还需要配合服务端日志才进行排查分析才可以。

  需要注意:

  ·不同浏览器下返回的error对象可能不同,需要注意兼容处理。

  ·需要注意避免addEventListener重复***。

  六、PromiseCatch

  在promise中使用catch可以非常方便的捕获到异步error,这个很简单。

  没有写catch的Promise中抛出的错误无法被onerror或try-catch捕获到,所以我们务必要在Promise

  中不要忘记写catch处理抛出的异常。

  解决方案:为了防止有漏掉的Promise异常,建议在全局增加一个对unhandledrejection的***,用来全局***Uncaught

  PromiseError。使用方式:

  window.addEventListener(""unhandledrejection"",function(e){

  console.log(e);

  });

  我们继续来尝试一下:

  window.addEventListener(""unhandledrejection"",function(e){

  e.preventDefault()

  console.log('捕获到异常:',e);

  returntrue;

  });

  Promise.reject('promiseerror');

  可以看到如下输出:

  那如果对Promise不进行catch呢?

  window.addEventListener(""unhandledrejection"",function(e){

  e.preventDefault()

  console.log('捕获到异常:',e);

  returntrue;

  });

  ewPromise((resolve,reject)=>{

  reject('jartto:promiseerror');

  });

  嗯,事实证明,也是会被正常捕获到的。

  所以,正如我们上面所说,为了防止有漏掉的Promise异常,建议在全局增加一个对unhandledrejection的***,用来全局***

  UncaughtPromiseError。

  补充一点:如果去掉控制台的异常显示,需要加上:

  event.preventDefault();

  七、VUEerrorHandler

  Vue.config.errorHandler=(err,vm,info)=>{

  console.error('通过vueerrorHandler捕获的错误');

  console.error(err);

  console.error(vm);

  console.error(info);

  }

  八、React异常捕获

  React16提供了一个内置函数componentDidCatch,使用它可以非常简单的获取到react下的错误信息

  componentDidCatch(error,info){

  console.log(error,info);

  }

  除此之外,我们可以了解一下:errorboundaryUI的某部分引起的JS错误不应该破坏整个程序,为了帮React

  的使用者解决这个问题,React16介绍了一种关于错误边界(errorboundary)的新观念。

  需要注意的是:errorboundaries并不会捕捉下面这些错误。

  1.事件处理器2.异步代码3.服务端的渲染代码4.在errorboundaries区域内的错误

  我们来举一个小例子,在下面这个componentDIdCatch(error,info)里的类会变成一个errorboundary:

  classErrorBoundaryextendsReact.Component{

  constructor(props){

  super(props);

  this.state={hasError:false};

  }

  componentDidCatch(error,info){

  //DisplayfallbackUI

  this.setState({hasError:true});

  //Youcanalsologtheerrortoanerrorreportingservice

  logErrorToMyService(error,info);

  }

  render(){

  if(this.state.hasError){

  //YoucanrenderanycustomfallbackUI

  return

Somethingwentwrong.

;

  }

  returnthis.props.children;

  }

  }

  然后我们像使用普通组件那样使用它:

  

  

  

  componentDidCatch()方法像JS的catch{}模块一样工作,但是对于组件,只有class类型的组件(class

  component)可以成为一个errorboundaries。

  实际上,大多数情况下我们可以在整个程序中定义一个errorboundary组件,之后就可以一直使用它了!

  九、iframe异常

  对于iframe的异常捕获,我们还得借力window.onerror:

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

  console.log('捕获到异常:',{message,source,lineno,colno,error});

  }

  一个简单的例子可能如下:

  

  

  十、Scripterror

  一般情况,如果出现Scripterror

  这样的错误,基本上可以确定是出现了跨域问题。这时候,是不会有其他太多辅助信息的,但是解决思路无非如下:

  跨源资源共享机制(CORS):我们为script标签添加crossOrigin属性。

  

  或者动态去添加js脚本:

  constscript=document.createElement('script');

  script.crossOrigin='anonymous';

  script.src=url;

  document.body.appendChild(script);

  特别注意,服务器端需要设置:Access-Control-Allow-Origin

  此外,我们也可以试试这个-解决ScriptError的另类思路:

  constoriginAddEventListener=EventTarget.prototype.addEventListener;

  EventTarget.prototype.addEventListener=function(type,listener,options){

  constwrappedListener=function(...args){

  try{

  returnlistener.apply(this,args);

  }

  catch(err){

  throwerr;

  }

  }

  returnoriginAddEventListener.call(this,type,wrappedListener,options);

  }

  简单解释一下:

  ·改写了EventTarget的addEventListener方法;

  ·对传入的listener进行包装,返回包装过的listener,对其执行进行try-catch;

  ·浏览器不会对try-catch起来的异常进行跨域拦截,所以catch到的时候,是有堆栈信息的;

  ·重新throw出来异常的时候,执行的是同域代码,所以window.onerror捕获的时候不会丢失堆栈信息;

  利用包装addEventListener,我们还可以达到「扩展堆栈」的效果:

  (()=>{

  constoriginAddEventListener=EventTarget.prototype.addEventListener;

  EventTarget.prototype.addEventListener=function(type,listener,options){

  +//捕获添加事件时的堆栈

  +constaddStack=newError(`Event(${type})`).stack;

  constwrappedListener=function(...args){

  try{

  returnlistener.apply(this,args);

  }

  catch(err){

  +//异常发生时,扩展堆栈

  +err.stack+='\n'+addStack;

  throwerr;

  }

  }

  returnoriginAddEventListener.call(this,type,wrappedListener,options);

  }

  })();

  十一、崩溃和卡顿

  卡顿也就是网页暂时响应比较慢,JS可能无法及时执行。但崩溃就不一样了,网页都崩溃了,JS

  都不运行了,还有什么办法可以监控网页的崩溃,并将网页崩溃上报呢?

  崩溃和卡顿也是不可忽视的,也许会导致你的用户流失。

  1.利用window对象的load和beforeunload事件实现了网页崩溃的监控。不错的文章,推荐阅读:Logging

  InformationonBrowserCrashes。

  window.addEventListener('load',function(){

  sessionStorage.setItem('good_exit','pending');

  setInterval(function(){

  sessionStorage.setItem('time_before_crash',newDate().toString());

  },1000);

  });

  window.addEventListener('beforeunload',function(){

  sessionStorage.setItem('good_exit','true');

  });

  if(sessionStorage.getItem('good_exit')&&

  sessionStorage.getItem('good_exit')!=='true'){

  /*

  insertcrashloggingcodehere

  */

  alert('Hey,welcomebackfromyourcrash,lookslikeyoucrashedon:'+sessionStorage.getItem('time_before_crash'));

  }

  2.基于以下原因,我们可以使用ServiceWorker来实现网页崩溃的监控:

  ·ServiceWorker有自己**的工作线程,与网页区分开,网页崩溃了,ServiceWorker一般情况下不会崩溃;

  ·ServiceWorker生命周期一般要比网页还要长,可以用来监控网页的状态;

  ·网页可以通过navigator.serviceWorker.controller.postMessageAPI向掌管自己的SW

  发送消息。

  十二、错误上报

  1.通过Ajax发送数据因为Ajax请求本身也有可能会发生异常,而且有可能会引发跨域问题,一般情况下更推荐使用动态创建img

  标签的形式进行上报。

  2.动态创建img标签的形式

  functionreport(error){

  letreportUrl='http://jartto.wang/report';

  ewImage().src=`${reportUrl}?logs=${error}`;

  }

  收集异常信息量太多,怎么办?实际中,我们不得不考虑这样一种情况:如果你的网站访问量很大,那么一个必然的错误发送的信息就有很多条,这时候,我们需要设置采集率,从而减缓服务器的压力:

  Reporter.send=function(data){

  //只采集30%

  if(Math.random()<0.3){

  send(data)//上报错误信息

  }

  }

  采集率应该通过实际情况来设定,随机数,或者某些用户特征都是不错的选择。

  十三、总结

  回到我们开头提出的那个问题,如何优雅的处理异常呢?

  1.可疑区域增加Try-Catch

  2.全局监控JS异常window.onerror

  3.全局监控静态资源异常window.addEventListener

  4.捕获没有Catch的Promise异常:unhandledrejection

  5.VUEerrorHandler和ReactcomponentDidCatch

  6.监控网页崩溃:window对象的load和beforeunload

  7.跨域crossOrigin解决

  其实很简单,正如上文所说:采用组合方案,分类型的去捕获异常,这样基本80%-90%的问题都化于无形。

免责声明

非本网作品均来自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其他问题,请及时与本网联系,我们将及时删除内容。

猜你喜欢

热点排行榜

教育部即将调整中小学上课时间,学生真的高兴坏了!
教育,是任何一个国家和民族的未来。如果没有了教育,那么这个国家和民族未来也会以前黑暗。随着知识在社会中的作用越来越大,人们也越来越重视教育。尤其是家长,为了能让孩子学习好,对于教育的投资可以说是不计代价!在许多人都越来越注重学习成绩的同时,孩子的学习压力却是越来越大,有的时候甚至孩子的睡眠时间都会严重不足。 如此一来虽然看似是孩子的学习成绩进步了,但是却严重影响了孩子的正常健康发育。如此
来看看在双减政策后,到底公立学校和私立学校有什么差距?
大部分的中小学生,都会选择在公立学校接受义务教育,但是随着教育“内卷”的情况越来越严重,不少学生家长会选择将孩子送到私立学校去上学,在这样的情况之下,中小学生的学习压力也越来越大,因此中小学生在上学的过程中,也会觉得非常疲惫。这种状态不*不利于学生们提高学习成绩,更不利于学生们成长,因此相关部门也是引起了高度重视。 随着“双减”政策的实行,学生们的学习压力也在逐渐减小,“双减”实行后,公
为了推行三胎,课本的封面也变成三胎了,来看看人社部怎么说的~
开学没几天,网络上就开始流传着热心家长们对语文课本的“新发现”:一年的时间,课本封面由二胎变成了三胎,妈妈也不打扮了,头发随便一扎,衣服还是去年那件,只是旧了。多了个娃,爸爸也不在家下棋了,估计为了养家加班挣钱去了。家长们口中的两个封面分别是统编语文教材五年级上册、六年级上册封面。这段“看图说话”因为贴近“三胎”的社会热点,迅速引发了众多网友的共鸣、转发。人民教育出版社在其公众号上进行了“辟谣”:
清华北大亚洲**新排名来啦!泰晤士公布了2022世界大学排名结果!
综合报道,当地时间2日,泰晤士高等教育特刊(Times Higher Education,简称THE)更新了**新2022年THE世界大学排名。中国高校排名再次上升,首次有两所大学进入前20名,创下亚洲**佳纪录。根据新发布的排名,北大和清华并列第16名,这是首次中国有两所大学进入前20名,也亚洲国家迄今为止的**高排名。此外,中国内地共有10所大学进入前200名。根据排名,牛津大学连续6年位列第一。美
怎么选择美国留学中介?选的时候一定要清醒!
此篇文章会把下面很多问题中的内容阐述的逻辑层次更简单分明一些,假使同学们如果没有太多时间,不妨粗略阅读下面的问题,大概了解下!我计划去美国留学入读硕士,想请教一下如何选择美国留学中介机构呢?美国留学中介选择策略:衡量自己的消费者心理选择美国留学中介机构请务必要依据你的需求进行相关选择。首先你需要询问自己,你申请是要干什么呢?这个问题就像是购买衣服和鞋,你买运动鞋,就不会去西装店。美国留学作为一个很
英语的单词怎么写才好看?学会这几个小习惯,你也能写的好看!
英语学习重视听说读写,其中的写作涉及标准的写作规范。以下是英语单词写法的介绍,供参考。1.倾斜。每个字母稍微向右倾斜,大约在5°~20°之间,但每个字母的倾斜必须一致,所以很漂亮。2.大写字母。大写字母都一样高,占上面的两个格子,顶部面向第一条线。3.小写字母。中间一格小写字母a、c、e、m、n、o、r、s、u、v、w、x、z写在中间一格中,上下抵抗,但不及格。小写字母B、D、H、K、L上端顶一线
乐读推出一年级20人在线小班:通过小班教学 建构积极有效的师生互动
随着全国各地中小学和幼儿园秋季开学时间的确定,幼小、初小衔接又成了热点话题,但究竟要如何“衔接”,并不是每位家长都有科学的认识。乐读20人在线小班面向一年级孩子,激发兴趣、培养习惯,希望科学有效地帮助孩子适应小学学习生活,实现从幼儿教育阶段到小学教育阶段的顺利过渡。从孩子喜闻乐见的事物入手,培养学习的兴趣小学生活泼好动,注意力持续时间短,不少孩子初入小学课堂可能会出现发呆、坐不住的情况。据此,家长
学而思网校的线下校区即将关闭,只因房租成本过高!
9月27日消息,据媒体报道,学而思老师群内告知家长,因运营成本过高,不足以支撑面授班运营,所有面授课转为在线班。并统一在10月9日中午12:00开启转线上功能。此外,多名学而思工作人员均表示线下校区将会关闭。业内人士指出,在高额的房租下,退租关店也许是**理智的做法。目前线下教培机构在节假日、休息日及寒暑假的营收能占到全年收入的一半以上,但是现在不让上课,商业模型该怎么搭,目前很多线下机构恐怕还没想
教育部又来消息了,以后这类竞赛要被管理了!速来看看!
9月23日,教育部举行新闻通气会,介绍规范校外培训机构管理制度建设有关情况。会上,教育部校外教育培训监管司负责人介绍,“双减”工作是一项长期性复杂性系统性的工程,必须注重当前和长远相统一,研究修订竞赛管理办法,将治理打着“国际”旗号的各类竞赛。教育部校外教育培训监管司负责人表示,加快预收费监管、加强培训机构党建等其他配套政策法规的制订进度。同时完善“营改非”流程,进一步明确过程中的公示期限、资产确
各大高校开学了,清华大学开学典礼的主题演讲走红了,这个主题真不错!
9月是开学季,很多人带着对大学的憧憬迈入校园。在清华大学开学典礼上,一段开学演讲走红。教师代表梅赐琪没有讲成功,而是讲失败。在他看来,与成功相比,失败能带给人更多可能性。以下是演讲全文:首先请允许我代表我的同事们向***(9月2日)入学的2021级同学们表示**热烈的祝贺!每一级的清华人都是特殊的,但是你们还是要更特殊一些。在人类和七种冠状病毒的遭遇之中,你们中的绝大多数见证了其中**危险的两次,一次懵