如何友好的处理js错误


写过程序的同学都是到,有时候我们在熬夜调试一些代码有多么沮丧,最后当你发现问题是你忽略的简单逗号或类似的东西时,我都可以肯定会笑出声来。但是,客户报的bug将带来更多的皱眉而不是微笑。

话虽如此,错误可能令人烦恼,而背后却是真正的痛苦。有什么可以让用户体验好,不会看着像科幻里一样包一堆乱码,尤其是客户端,这就是我想解释一下JavaScript中称为try / catch的东西。

什么是JavaScript中的try/catch

try/catch块基本上是用来在JavaScript处理错误的。当你不希望脚本中的错误阻塞代码时,可以使用考虑使用它。

尽管看起来好像可以使用if语句轻松完成这些事情,但是try/catch 除了可以完成if/else语句可以完成的工作外,还为你带来很多好处。

  try{
    //...你的代码
  }catch(e){
    //...你的代码
  }

使用try语句可以测试代码块是否存在错误,并且不会阻塞代码执行。例如:

  try{ 
    getListData() // getListData is not defined 
  }catch(e){
    alert(e)
  }

这就是构造try/catch的方式。你将代码放在try块中,如果出现错误,JavaScript会立即控制catch语句,并按照你的代码执行。在这种情况下,它会警告你该错误。

所有JavaScript错误实际上都是包含两个属性的对象:名称(例如,Error,syntaxError等)和实际错误信息。这就是为什么当e发出警报时,会得到类似ReferenceError的错误:undefined getListData。

与JavaScript中的所有其他对象一样,你可以决定以不同的方式显示错误提示,例如e.name(ReferenceError)和e.message。

但老实说,这与JavaScript的功能并没有真正的不同。那么,try / catch语句的好处是什么?

如何使用try/catch语句

throw

try/catch的优点之一是它能够显示你自己的自定义创建的错误。这称为抛错(throw error)。
在你不希望JavaScript显示这种晦涩难懂的情况下,可以使用throw语句抛出错误(异常)。该错误可以是字符串,布尔值或对象。如果有错误,catch语句将显示你抛出的错误。(用户就不会看到乱码了,这样用户的反感情绪也不会那么大了)

let num =prompt("输入一个大于30小于40的数字")
try { 
  if(isNaN(num)) {
    throw new Error("不是一个数字(☉。☉)!");
  }else if (num>40) {
    throw new Error("数字大于40了");
  }else if (num <= 30) {
    throw new Error("数字小于30了");
  }
}catch(e){
  alert(e) 
}

这是自定义的错误,这些我们在写代码的时候基本已经做了友好的判断了,更多的是我们在业务中无法预料的错误,通过将错误与JavaScript构造函数错误一起抛出,我们可以更进一步。

基本上,JavaScript将错误分为六类:

  • EvalError - eval函数中发生错误。
  • RangeError - 发生了超出范围的数字。
  • ReferenceError - 使用尚未声明的变量
  • SyntaxError - 出现语法错误时抛出;
  • TypeError - 你使用的值超出预期类型的​​范围;
  • URI(统一资源标识符)错误-如果你在URI函数中使用非法字符,则会引发URIError。

因此,有了这一切,我们很容易引发类似的错误throw Error。在这种情况下,错误的名称将为Error,并且消息catch里。你甚至可以继续创建自己的自定义错误构造函数,例如:

  try {
    getDataList();
  } catch (e) {
    if (e instanceof EvalError) {
      alert(e.name + ":" + e.message);
    } else if (e instanceof RangeError) {
      alert(e.name + ": " + e.message);
    } 
  }

而且,你可以轻松地在任何地方使用此功能throw new Error();
我们已经了解了try/catch及其如何防止脚本阻塞,但实际上取决于具体情况。让我们看下面这个例子:

try{ 
  console.log({{}}) 
}catch(e){ 
  alert(e.message) 
} 
console.log("最终的执行")

但是当你尝试使用try语句时,它仍然不起作用。这是因为JavaScript中有两种主要类型的错误;解析时错误运行时错误或异常

解析时错误是代码内部发生的错误,主要是因为引擎无法解析代码。

例如,从上面看,JavaScript无法理解花括号的含义,因此,你的try/catch在这里没有作用。

运行时错误是在有效代码中发生的错误,而这些正是try/catch必将发现的错误。

try{ 
  test = x + 100; 
} catch(e){ 
  alert("x参数未定义")
} 
alert("程序正常")

上面的代码是有效的,并且try/catch会捕获到运行时的错误。

Finally

Finally标识没有错之后执行的代码,或者捕获错误后该怎么执行,他是你的try/catch块最后一条语句。
对于finally,你基本上是说,无论try/catch中发生什么(错误或没有错误),finally语句中的此代码都会运行。例如:

let test = '';
try{ 
  if(data === "") {
    throw new Error("test为空");
  }else {
    alert(`hello ${data}`);
  }
} catch(e){ 
  alert(e) 
} finally { 
  alert("我时最后一条语句")
}

嵌套try块

你也可以嵌套try块,但是与JavaScript中的其他所有嵌套(例如if,for等)一样,它往往变得笨拙且不可读,因此,我建议你不要这样做。
嵌套try块为你提供了将一个catch语句用于多个try语句的优势。当然你也可以决定为每个try块编写一个catch语句,如下所示:

try { 
  try { 
    throw new Error('test');
  } catch(e){
    console.log(e) 
  } finally { 
    console.log('finally'); 
  } 
} catch (ex) { 
  console.log('ex error '+ex); 
}

在这种情况下,外部try块不会有任何错误,因为它没有错。该错误来自内部try块,并且它已经处理了(它具有自己的catch语句)。

像这样面考虑的问题:

try { 
  try { 
    throw new Error('inner catch error'); 
  } finally {
    console.log('finally'); 
  } 
} catch (ex) { 
  console.log(ex);
}

上面的代码的工作原理略有不同:错误发生在内部try块中,没有catch语句,但是出现了finally语句。

需要注意的是try/catch语句可以用三种不同的方式来写:try…catch,try…finally,try…catch…finally,但错误是这种内在的。

这种内部尝试的最后声明肯定会起作用,因为就像我们前面说过的那样,无论try / catch中发生什么,它都可以起作用。但是,即使外部尝试没有错误,也仍然可以控制捕获以记录错误。甚至更好的是,它使用我们在内部try语句中创建的错误,因为该错误来自那里。

如果我们要为外部尝试创建一个错误,它将仍然显示所创建的内部错误,但内部错误会捕获到自己的错误。

你可以通过注释掉内部错误代码来使用下面的代码。

try { 
  try { 
    throw new Error('内部 error');
  } catch(e){ //comment this catch out
    console.log(e) 
  } finally { 
    console.log('finally'); 
  } 
  throw new Error("外部 error") 
} catch (ex) { 
  console.log(ex);
}

重新抛出错误

catch语句实际上捕获了所有发生的错误,有时我们可能不希望这样。例如,

"use strict" 
let x=parseInt(prompt(" 请输入一个小于 5 的数字 ")) 
try{ 
  y=x-10 
  if(y>=5) {
    throw new Error(" y 不小于 5") 
  } else{
    alert(y);
  }
}catch(e){ 
  alert(e) 
}

假设输入的数字小于5(“使用严格”的目的是指示代码应在“严格模式”下执行)。在严格模式下,不能使用未声明的变量。

我希望try语句不会引发y的错误(当y的值大于5时,这几乎是不可能的)。上面的错误应该是因为y不小于输入的数字,并且不是y是undefined。

在这种情况下,你可以检查错误的名称,如果不是你想要的名称,则将其重新抛出:

"use strict" 
let x = parseInt(prompt("请输入一个小于 5 的数字"))
try{
  y=x-10 
  if(y>=5) {
    throw new Error("YYYY");
  }else{
    alert(y);
  }
}catch(e){ 
  if(e instanceof ReferenceError){ 
    throw e
  }else alert(e) 
} 

这将简单地将错误重新抛出,以供另一个try语句在此处捕获阻塞脚本继续执行。当你只想监视特定类型的错误,而由于疏忽可能发生错误导致代码报错,此功能很有用。

适合使用try/catch的场景

因此,不要把判断 null ,undefined,这种都用try catch 。
而是尽量用在不可知的错误捕获上,而不是未知的错误。比如用来捕获宿主对象或者ECMAScript抛出的异常。

NodeJS里大多数error都是用来处理异常的,因为异常是不可避免的,例如数据库挂了,网络错误,你虽然知道有可能,但是不知道何时发生,这些异常你需要捕捉或者传给上层。而错误处理,则是一些基本的判定,可以从代码级别避免其发生,可预知可推测,如果发生了,不是系统问题,而是你的程序有bug了。

对于NodeJS来说,两种错误都时刻需要注意,特别是系统错误,因为不可预知,需要大量代码来catch错误,传递错误,最后统一处理。

结论

到这里我们的try/catch就解释完了,基本包含了常用到的场景。


文章作者: Duke
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Duke !
评论
 本篇
如何友好的处理js错误 如何友好的处理js错误
错误和错误在编程中是不可避免的,有一部分是认为的,也有一部分是及其无法分析改怎么处理的,在JavaScript中尝试/捕获-如何处理JS中的错误。
2021-03-21
下一篇 
使用 D3.js 创建可交互的柱状图 使用 D3.js 创建可交互的柱状图
我会在此文中介绍使用 D3.js 的过程,以及通过一个简单的柱状图示例演示库的基本使用。读完此文后,你将学到如何轻松创建类似的 D3.js
2021-02-20
  目录