详解JavaScript错误捕获

作者:如沐春风x 时间:2024-04-30 09:53:22 

目录
  • 一、基本使用与逻辑

  • 二、特性

  • 三、错误对象

  • 四、较好的catch和throw策略

  • 五、Promise的错误处理

  • 六、性能损耗

一、基本使用与逻辑

使用


try{
   //code....
}catch(err){
   //error handling
}finally{
   //no matter what happens in the try/catch (error or no error), this code in the finally statement should run.
}

逻辑

详解JavaScript错误捕获

二、特性

try...catch 仅适用于运行时错误,解释阶段错误无法正常工作


try{
   {{{{{{{
}catch(err){
   console.error(err)
}
//引擎在‘parse-time'出错,导致无法理解代码,因此无法捕捉

try...catch 只能同步工作


try{
   setTimeout(function(){
       undefinedVariable;
   },1000)
}catch(err){
   console.error(err)
}
//setTimeout的回调函数执行时,引擎已经离开try...catch结构

finally 能让try块中的return语句失效


function test(){
 try {
   return 1;
 } catch(error) {
   return 2;
 } finally {
   return 3;
 }
}
console.log(test());
//3

三、错误对象

当程序发生error,js内部会生成一个包含error细节的对象,该对象会被作为参数传进catch

对于所有内置错误,错误对象具有两个主要属性

  • name 错误类型

  • message 文本类型的错误信息

  • stack (非标准属性)发生错误时的调用栈信息,主要用于调试


try {
 lalala; // error, variable is not defined!
} catch (err) {
 alert(err.name); // ReferenceError
 alert(err.message); // lalala is not defined
 alert(err.stack); // ReferenceError: lalala is not defined at (...call stack)

// Can also show an error as a whole
 // The error is converted to string as "name: message"
 alert(err); // ReferenceError: lalala is not defined
}

理论上,我们可以throw任何东西作为错误对象,但最好的习惯是throw一个具有name,message的对象,以便和内置错误对象保持兼容

番外:内置的错误对象

对象含义
ReferenceError引用未定义变量时触发
SyntaxError使用不合法的语法结构时触发
TypeError值得类型非预期时触发
URIError错误使用全局URI函数如encodeURI()、decodeURI()等时触发
RangeError对Array构造函数使用错误的长度值,对Number.toExponential()、Number.toFixed()或Number.toPrecision()使用无效数字等
EvalError全局函数eval()中发生的错误

四、较好的catch和throw策略

catch错误不单单是为了防止程序挂掉,更重要的目的是方便调试,找bug,所以对错误的处理策略,稍微可以体现出码者的优雅性

俗话说的好,码者,人恒雅也,尽量遵循一个原则,catch只处理自己知道的错误

举个梨子


let json = '{ "age": 30 }';
try{
 let user = JSON.parse(json);  
 alert( user.name );
} catch (err) {
 console.error('JSON Error:'+err);
}

上述例子的catch策略能保证程序正常,因为catch块能catch内部所有的错误,无论是JSON.parse出错还是user.name不存在报错,都能被catch到,但两种错误都用同一种打印是不利于调试的,写成下面这样会好一点


let json = '{"age":30}'
try{
 let user =  JSON.parse(json);
 alert(user.name)
}catch(err){
  if(err instanceof SyntaxError){
      console.error('JSON Error:'+err);
  }
  else throw err;
}

每个catch块处理自己知道得,可能会出现得错误,就是说,编程人员在编程的时候,catch那些预料到的错误,而将可能自己没料到的错误抛到外面。

五、Promise的错误处理

众所周知,Promise是会吞掉error的,因为promise的实现就在内部对所有error进行了捕获,且捕获到的error不是向外抛出(外指promise之外),而是沿着链找到最近的onreject回调传入,所以promise的错误处理只有两种办法

  1. 设置onreject回调

  2. 全局捕获

举个栗子


try{
   new Promise((resolve,reject)=>{
       throw new Error('promise error')
   }).catch(()=>{
       //错误在最近的onreject回调被捕获
       console.error(err);
   })
}catch(err){
   //永远不会执行,promise吞掉error
   console.error(err);
}

另外需要注意,无论是执行者函数(executor)和还是 promise 的处理程序(handler),内部发生的错误统统吞掉,相当于被隐式catch,error会自动找到最近的onreject回调传进去


try{
   new Promise((resolve,reject)=>{
       resolve();
   }).then(()=>{
       throw new Error('promise then error');
   }).catch((err){
       console.error(err);
   })
}catch(err){
   //地球毁灭之前都不会执行
   console.error(err)
}

同理,在错误找到onreject传进去之前,经过的then注册的onfulfilled回调统统失效,直到找到onreject回调,处理之后,onreject回调之后的onfulfilled回调才正常


try {
   new Promise((resolve, reject) => {
       throw new Error('promise error')
   }).then((ret) => {
       //错误没有处理,失效
       console.log('then1:' + ret)
   }).catch((err) => {
       //错误处理了,后序正常
       console.error(err);
       return 'handled'
   }).then((ret) => {
       //正常执行
       console.log('then2' + ret);
   })
} catch (err) {
   //同样的,人类毁灭之前都不会执行
   console.error(err)
}

// Error:promise error
//then2handled

那整条链一个catch都没设置会怎么样呢?

那这个error就会击穿地心,一直穿透到全局,根据宿主环境的不同触发不同的全局事件,比如说浏览器中会触发 unhandledrejection事件,node环境中也会触发unhandledRejection事件,一般会对这事件进行监听,再显示信息给编程人员或者用户

番外1:chromium / v8 / v8 / 3.29.45 的 Promise内部错误捕捉

详解JavaScript错误捕获

番外2:async/await错误捕捉

六、性能损耗

After V8 version 6 (shipped with Node 8.3 and latest Chrome), the performance of code inside try-catch is the same as that of normal code. ------ 爆栈网

(稍微测了一下,相差无几)

来源:https://juejin.cn/post/6953230639726493733

标签:JavaScript,错误,捕获
0
投稿

猜你喜欢

  • jRaiser与jQuery的冲突问题

    2010-07-27 12:36:00
  • 如何用拦截表单的方法上传图片?

    2010-06-16 09:50:00
  • Pytorch中的VGG实现修改最后一层FC

    2023-03-08 07:08:48
  • 清理你的CSS

    2009-10-06 15:11:00
  • oracle 彻底删除方法

    2024-01-19 10:20:57
  • SecureCRTSecure7.0查看连接密码的步骤

    2021-01-28 07:34:14
  • Python图像处理之图像的灰度线性变换

    2021-12-16 22:30:58
  • 利用JS打造黑客代码雨效果

    2024-05-03 15:05:16
  • sqlserver 动态创建临时表的语句分享

    2012-01-29 17:54:37
  • Python中层次聚类的详细讲解

    2022-07-02 06:07:13
  • python正则匹配查询港澳通行证办理进度示例分享

    2021-05-09 19:29:55
  • xmlhttp 乱码 比较完整的解决方法 (UTF8,GB2312)

    2008-05-02 21:02:00
  • Go语言init函数详解

    2024-05-11 09:18:31
  • python 绘制场景热力图的示例

    2022-01-22 07:03:21
  • pandas dataframe添加表格框线输出的方法

    2021-11-28 01:34:41
  • golang通过mysql语句实现分页查询

    2024-01-23 13:30:03
  • Python实现的IP端口扫描工具类示例

    2023-02-25 07:22:25
  • Python Asyncio中Coroutines,Tasks,Future可等待对象的关系及作用

    2021-02-09 02:01:47
  • Python完全新手教程

    2021-08-19 18:38:06
  • Go结合Gin导出Mysql数据到Excel表格

    2024-01-21 05:43:50
  • asp之家 网络编程 m.aspxhome.com