js:try…catch…finally捕获错误处理的用法实例

我们在JS编程时,特别在调试阶段,捕获错误是非常有必要的,这将大大提高我们的勘错效率。而要把程序编写得更安全坚固,错误处理也必不可少。

JS存在一种语法构造try…catch,该语法构造使我们可以“捕获”错误,这使脚本可以执行得更加合理而不会因遇到“死亡脚本”导致程序执行失败。

 
js: try-catch-finally捕获错误

“ try…catch”语法

try…catch构造有两个主要块:trycatch

try {

  // 代码…

} catch (err) {

  // 错误处理

}

它是这样的:

首先,执行try {...}中的代码。

如果没有错误,则将忽略catch(err):执行到达try的结尾并继续,跳过catch

如果发生错误,则try执行将停止,控制流向catch(err)的开头。该err变量(我们可以使用它的任何名称)将包含发生了什么详细的错误对象。

因此,try {...}块内的错误不会杀死脚本,我们有机会在catch中处理它。

让我们看一些例子。

一个无错误的示例:显示(1)(2)

try {

  alert(‘开始运行try’);  // (1) <–

  // …这里无错误

  alert(‘结束运行try’);   // (2) <–

} catch (err) {

  alert(‘catch被忽略,因为这里无错误’); // (3)

}

trying >>

带有错误的示例:显示(1)(3)

try {

  alert(‘开始运行try’);  // (1) <–

  lalala; // 错误,变量未定义!

  alert(‘结束运行try(永远不会到达)’);  // (2)

} catch (err) {

  alert(‘出现错误!’); // (3) <–

}

trying >>

try…catch 仅适用于运行时错误

为了try…catch工作,代码必须是可运行的。换句话说,它应该是有效的JavaScript。

如果代码在语法上是错误的,那么它将无法正常工作,例如,它具有不匹配的花括号:

try {
  {{{{{{{{{{{{
} catch (err) {
  alert(“引擎不懂这个代码,无效代码”);
}

trying >>

JavaScript引擎首先读取代码,然后运行它。在读取阶段发生的错误称为“解析时”错误,并且无法恢复(从该代码内部),那是因为引擎无法理解代码。

因此,try…catch只能处理有效代码中发生的错误。这种错误称为“运行时错误”,有时也称为“异常”。

try…catch 同步工作

如果在“预定的”代码中发生异常,例如在trysetTimeout,则try…catch不会捕获到该异常:

try {
  setTimeout(function() {
    noSuchVariable; // 脚本在这里停止
  }, 1000);
} catch (err) {
  alert( “不会执行” );
}

trying >>

这是因为函数本身是在引擎已离开try…catch构造时稍后执行的。

要在预定函数内捕获异常,try…catch必须在该函数内:

setTimeout(function() {
  try {
    noSuchVariable; // try…catch 处理这个错误!
  } catch {
    alert( “错误被捕获!” );
  }
}, 1000);

trying >>

try…catch…finally

try…catch构造可能还包含一个代码子句:finally

如果存在,它将在所有情况下运行:

  • try之后,如果没有错误,
  • catch之后,如果有错误。

扩展语法如下所示:

try {
   … 尝试执行这里代码 …
} catch (err) {
   … 处理错误 …
} finally {
   … 总是执行 …
}

 
try…catch…finally执行流程

尝试运行以下代码:

try {
  alert( ‘try’ );
  if (confirm(‘出错?’)) BAD_CODE();
} catch (err) {
  alert( ‘catch’ );
} finally {
  alert( ‘finally’ );
}

trying >>

该代码有两种执行方式:

  1. 如果你对“出错?”回答“是”,则try -> catch -> finally
  2. 如果您说“否”,则try -> finally

finally 和 return

finally子句适用于try…catch的任何退出,这里包括一个显式的return

在下面的示例中,有一个returnin try。在这种情况下,finally在控件返回外部代码之前执行。

function func() {

  try {
    return 1;

  } catch (err) {
    /* … */
  } finally {
    alert( ‘finally’ );
  }
}

alert( func() ); // 首先执行finally里的alert, 然后再执行try

trying >>

try…finally

try…finally不带catch子句的构造也很有用。当我们不想在这里处理错误时,我们可以应用它,但是要确保我们启动的过程已经完成。

function func() {
  // 开始做一些需要完成的事情
  try {
    // …
  } finally {
    // 即使全部死亡都完成那件事
  }
}

try…catch有无finally的区别

比较两个代码片段。

1、第一个用于finally执行以下代码try…catch

try {
   // 工作 工作
} catch (err) {
   // 处理错误
} finally {
   清洗工作空间
}

2、第二个片段把清洗空间放在try…catch的后面:

try {
   // 工作 工作
} catch (err) {
   // 处理错误
}

清洗工作空间

我们肯定需要在工作后进行清理,无论是否有错误都没有关系。

两个代码片段是否相等?在这里使用finally是否有优势?下面两个例子说明了使用finally的优势。

当我们看一个函数内部的代码时,区别变得很明显。

如果“跳出”,则try…catch的行为会有所不同。

例如,当有一个returntry…catch内部时,该finally在任何来自try…catch的出口工作,甚至是通过return声明。catch将在执行完finally代码之后再执行。

function f() {
  try {
    alert(‘开始’);
    return “结果”;
  } catch (err) {
    /// …
  } finally {
    alert(‘清洗!’);
  }
}

f(); // 清洗!

trying >>

又例如,当函数内有throw时:

function f() {
  try {
    alert(‘开始’);
    throw new Error(“一个错误”);
  } catch (err) {
    // …
    if(“can’t handle the error”) {
      throw err;
    }

  } finally {
    alert(‘清洗!’)
  }
}

f(); // 清洗!

trying >>

finally是保证在这里进行清理。如果仅将代码放在的f()末尾,则在这些情况下将无法运行该代码。