优雅处理前端异常的几种方式推荐

目录
  • 一、为什么要处理异常?
  • 二、需要处理哪些异常?
  • 三、处理异常的方式有哪些?
    • 1、try-catch
    • 2、window.onerror
    • 3、window.addEventListener
    • 4、Promise catch
    • 5、vue errorHandler
    • 6、 react 异常捕获
    • 7、跨域
  • 四、总结

一、为什么要处理异常?

1、未雨绸缪,尽早发现问题

2、让异常变得可控,避免影响呈现结果

3、增强用户体验

4、完善的前端方案

二、需要处理哪些异常?

1、JavaScript 语法错误、代码异常

2、异步请求异常

3、静态资源加载异常

4、Promise 异常

5、跨域

6、崩溃与渲染异常

三、处理异常的方式有哪些?

1、try-catch

我们可以使用 try-catch 对同步代码运行异常进行捕获。

例如:

try {
  let name = 'leo';
  console.log(age);
} catch(e) {
  console.log('捕获到异常:',e);
}

// 捕获到异常: ReferenceError: age is not defined

try-catch 无法捕获语法错误和异步错误。

例如:

try {
  let name = 'leo;   // 缺少一个单引号,属于语法错误,在开发阶段便提示出来
  console.log(age);
} catch(e) {
  console.log('捕获到异常:',e);
}
// Uncaught SyntaxError: Invalid or unexpected token
try {
  setTimeout(() => {
    undefined.map(v => v*2);
  }, 1000)
} catch(e) {
  console.log('捕获到异常:',e);
}
 

由于 setTimeout 属于异步,try-catch 并没有捕获到,查看日志

// Uncaught TypeError: Cannot read property 'map' of undefined

2、window.onerror

我们可以使用 window.onerror 对 JavaScript 运行错误时进行捕获。

window.onerror = function(message, source, lineNo, colNo, error) {
  console.log('捕获到异常:',{message, source, lineNo, colNo, error});
}

/**
* message   错误信息
* source    出错文件
* lineNo    行号
* colNo     列号
* error     Error对象(对象)
*/

同步运行错误

window.onerror = function(message, source, lineNo, colNo, error) {
  console.log('捕获到异常:',{message, source, lineNo, colNo, error});
}
leo;

捕获到异常

语法错误

window.onerror = function(message, source, lineNo, colNo, error) {
  console.log('捕获到异常:',{message, source, lineNo, colNo, error});
}
let name = 'leo

与 try-catch 一样,无法捕获语法错误。

异步运行错误

window.onerror = function(message, source, lineNo, colNo, error) {
  console.log('捕获到异常:',{message, source, lineNo, colNo, error});
}
setTimeout(() => {
  leo;
},1000)

捕获到异常

window.onerror 在捕获到错误时,会向上抛出,如上例,控制台会出现

我们可以在函数里面使用 return true,使异常不向上抛出,此时控制台不会显示如上错误信息

window.onerror = function(message, source, lineNo, colNo, error) {
  console.log('捕获到异常:',{message, source, lineNo, colNo, error});
  return true;   // 异常不向上抛出
}
setTimeout(() => {
  leo;
},1000)

window.onerror 最好写在所有 JavaScript 脚本前面,否则有可能捕获不到异常;

window.onerror 无法捕获语法异常、静态资源异常、接口请求异常;

window.onerror 主要用来捕获意料之外的异常,而 try-catch 则是用来捕获可预见的异常。

3、window.addEventListener

我们可以使用 window.addEventListener 对静态资源加载异常与接口请求异常进行捕获。

<scritp>
window.addEventListener('error', (error) => {
    console.log('捕获到异常:', error);
}, true)
</script>
<img src="../../assets/test.png">

捕获到异常

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

由于网络请求异常不会事件冒泡,因此必须在捕获阶段将其捕捉到才行,但是这种方式虽然可以捕捉到网络请求的异常,但是无法判断状态码是 404 还是其他比如 500 等等,所以还需要配合服务端日志才进行排查分析才可以。

不同的浏览器返回的 error 对象可能不一样,需要做兼容;

避免 addEventListener 重复监听。

4、Promise catch

我们可以使用 Promise 中的 catch 捕获异步错误。

new Promise((resolve,reject) => {
  reject("执行失败!")
}).catch(error => {
  console.log("捕获到异常:",error)
})

捕获到异常

有时候我们在写 Promise 可能会漏掉 catch,所以建议在全局增加一个对 unhandledrejection 的监听,用来全局监听 Uncaught Promise Error。

window.addEventListener("unhandledrejection", function(e){
  e.preventDefault()
  console.log('捕获到异常:', e);
});
new Promise((resolve,reject) => {
  reject("执行失败!")
})

捕获到异常

添加  event.preventDefault(); 可以去掉控制台的异常显示信息。

5、vue errorHandler

我们可以使用 errorHandler 对 vue 组件中所抛错误的捕捉与处理。

Vue.config.errorHandler = (err, vm, info) => {
  console.error(err);
  console.error(vm);
  console.error(info);
}

// 某个组件的 mounted
const error = new Error('test error');
error.code = -1;
throw error;

捕获到异常

6、 react 异常捕获

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

componentDidCatch(error, info) {
  console.log(error, info);
}

除此之外,也可以使用错误边界 error boundary,此处不展开。

7、跨域

资源跨域可以为 script 标签添加 crossOrigin 属性。

<script src="http://localhost:3000/main.js" crossorigin></script>

也可以动态添加 JavaScript 脚本

const script = document.createElement('script');
script.crossOrigin = 'anonymous';
script.src = url;
document.body.appendChild(script);

四、总结

处理异常方式 说明
try-catch 可预见、可疑区域
window.onerror 全局捕获 JavaScript 异常
window.addEventListener 全局捕获静态资源异常
Promise catch 捕获 Promise 异常,也可使用 unhandledrejection 进行全局捕获
vue errorHandler 捕获 vue 异常
react 异常捕获 捕获 react 异常
crossOrigin 解决 JavaScript 脚本跨域

到此这篇关于优雅处理前端异常的几种方式文章就介绍到这了,更多相关优雅处理前端异常内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

参考:如何优雅处理前端异常? - Jartto's blog

时间: 2022-08-06

详解js前端代码异常监控

阅读目录 什么是前端代码异常 window.onerror 写一个js报错的上报库 注意点: 缺点: 在平时的工作,js报错是比较常见的一个情景,尤其是有一些错误可能我们在本地测试的时候测试不出来,当发布到线上之后才可以发现,如果抢救及时,那还好,假如很晚才发 现,那就可能造成很大的损失了.如果我们前端可以监控到这种报错,并及时上报的话,那我们的问题就比较好解决了.所以我们今天来聊聊前端代码的异常监控 什么是前端代码异常  一般语法错误以及运行时错误,浏览器都会在console里边体现出错误信息

前端异常502&nbsp;bad&nbsp;gateway的原因和解决办法

 502 Bad Gateway服务器作为网关或者代理时,为了完成请求访问下一个服务器,但该服务器返回了非法的应答. 解决办法是:再刷新一下网页或清理一下电脑的缓冲文件在打开你想打开的网页就好了. 一般情况下,这种办法是行得通的,但也不排除你所访问的网页被屏蔽的可能,如果你所访问的网页被屏蔽的话,就不管你怎么刷新也是没用的了. 502 bad gateway报错形成 1.什么是502 bad gateway 报错 简单来说502是报错类型代码bad gateway错误的网关 2.产生502错误的

当master down掉后,pt-heartbeat不断重试会导致内存缓慢增长的原因及解决办法

最近同事反映,在使用pt-heartbeat监控主从复制延迟的过程中,如果master down掉了,则pt-heartbeat则会连接失败,但会不断重试. 重试本无可厚非,毕竟从使用者的角度来说,希望pt-heartbeat能不断重试,直到重新连接上数据库.但是,他们发现,不断的重试会带来内存的缓慢增长. 重现 环境: pt-heartbeat v2.2.19,MySQL社区版 v5.6.31,Perl v5.10.1,RHEL 6.7,内存500M 为了避免数据库启停对pt-heartbea

java 出现NullPointerException的原因及解决办法

java 出现NullPointerException的原因及解决办法 日常开发过程中,最常见的异常莫过于NullPointerException,之前的时候,只是知道去找到报错的位置,然后去解决它,最近有空学习C语言,就去深究了下NullPointerException异常的本质. 发生NullPointerException的情况: 调用 null 对象的实例方法. 访问或修改 null 对象的字段. 如果一个数组为null,试图用属性length获得其长度时. 如果一个数组为null,试图

Vue中 v-if/v-show/插值表达式导致闪现的原因及解决办法

在开发过程中经常会发现当页面明明不应该出现的元素或内容会闪现一下然后消失,最近研究了一下这个问题的原因和解决办法,这里和大家分享一下. 1.闪现的原因 这个问题是因为Vue要等到HTML DOM加载完成后才会执行JS的编译,所以对使用的指令如 v-if , v-show 或者使用了插值表达式 {{}} 都会出现闪现的情况.因为在这些判断条件或表达式执行之前,DOM已经渲染出来了,之后Vue才会执行相应的JS代码. 2.解决的办法 其实在了解了原因之后我们就有了大概的思路,既然是在JS执行之前会出

Mysql/MariaDB启动时处于进度条状态导致启动失败的原因及解决办法

今天打开网站突然发现网站无法打开,后来通过SSH登陆服务器发现MARIADB数据库没有启动成功,再次启动还是无法成功启动,一直处于启动进度条,进度条结束后提示ERROR.查看日志出现以下错误: InnoDB: Unable to lock ./ibdata1, error: 11 后经调试发现是因为MariaDB数据库所在分区已经满了,造成无法启动. 只有将MariaDB数据库存放数据目录移动到另外一个磁盘份额比较大的分区或者将当前分配删除一些不必要的文件. 移动办法: 1.停掉mysql服务器

Oracle用户被锁的原因及解决办法

在登陆时被告知test用户被锁 1.用dba角色的用户登陆,进行解锁,先设置具体时间格式,以便查看具体时间 SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'; Session altered. 2.查看具体的被锁时间 SQL> select username,lock_date from dba_users where username='TEST'; USERNAME LOCK_DATE TEST 2009-03-1

BootStrap.css 在手机端滑动时右侧出现空白的原因及解决办法

最近的一个项目 前台使用了 bootstrap.css + angularjs, 后台只处理数据(用的php,处理结果直接 json_encode($arr),非常爽).一直在Chrome的仿真机测试非常完美, 没有进行真机测试.完成后,到手机测试时傻了,左右滑动页面时,竟然出现了一个 空白的竖条(如下图所示).判断是margin-right 设置的长度所致,检查css,并没有相关代码.看来问题出现在了 bootstrap .虽然不影响 程序的使用,但是感觉非常别扭,一定要修复它. 检查页面,发

Android开发中requestfocus()无效的原因及解决办法

前言 最近做公司项目的时候,经常会遇到一个问题,就是我为某个控件如EditText设置requestfocus()的时候不管用,比如说登陆的时候,我判断下用户输入的密码,如果正确就登陆,错误就提示密码错误,并且输入框获取焦点,但是实际中确不起作用 package com.example.hfs.requestfocusdemo; import android.content.Intent; import android.support.v7.app.AppCompatActivity; impo

MySQL ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO) 的原因分解决办法

MySQL ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO) 的解决办法和原因 这两天下载了MySQL5.7.11进行安装,发现到了初次使用输入密码的时候,不管怎样都进不去,即使按照网上说的在mysqld 下面添加skip-grant-tables也是不行,后来研究了两天,终于找出原因和解决办法. 复制代码 代码如下: [mysqlld] skip-grant-tables: 原因

PHP验证码无法显示的原因及解决办法

PHP验证码无法显示的原因及解决办法 一.如果是utf-8,就有可能是BOM没有清除 二.在Header("Content-type: image/PNG"); 之前有输出 三.第一行PHP隐藏了代码,如空格,回车等. 解决代码: $image_width=70; //设置图像宽度 $image_height=18; //设置图像高度 $new_number=$_GET[num]; //$new_number=5; $num_image=imagecreate($image_width

基于Bootstrap实现的下拉菜单手机端不能选择菜单项的原因附解决办法

基于Bootstrap做的下拉菜单在电脑浏览器中可正常使用,在手机浏览器中能弹出下拉列表,却不能选择列表中的菜单项,通过自己百度查找原因将bootstrap脚本文件中的ontouchstart 替换为 disable-ontouchstart可以解决,替换后并不能解决.(红米手机UC浏览器不支持,小米手机UC浏览器正常,其他暂时未测试) jquery:v1.11.2 bootstrap:v3.3.4 以下为前台页面代码: <div class="input-group">