try-catch-finally

@JChehe 2019-05-14 14:04:39发表于 JChehe/blog

基础

try {
    // 可能会导致错误的代码
} catch (err) {
    // 在错误发生时怎么处理
} finally {
    // 即使报错始终执行
}

try-catch 是针对可能抛出错误代码,避免因报错而中断整体代码的运行。

try 不能单独使用,必须搭配 catchfinally 使用。

try 代码块内抛出错误时,则从该代码行起后续代码将不会执行(当前代码块),直接进入 catch。若 try 没有抛出错误,则会跳过 catch

try 代码块内抛出错误时,但未定义 catch,即只定义了 finally,那么仍会中断整体代码的运行。

throw 语句用来抛出一个用户自定义的异常。当前函数的执行将被停止(throw 之后的语句将不会执行),并且控制权将被传递到调用堆栈中的第一个 catch 块。如果调用者函数中没有catch 块,程序将会终止。

延伸:return throw new Error() 是错误的语法 Uncaught SyntaxError: Illegal return statement。MDN 上 return [[expression]]; return 后面接的是表达式而不是语句,而 throw 是语句。另外,throw 本身也会中断当前代码块后续代码的运行。

无论是否抛出异常 finally 子句都会执行。即使没有 catch 子句处理异常。

当发生异常时,可以使用 finally 子句使您的脚本以更优雅的方式处理错误的情况。例如,释放已经绑定的资源等。

openMyFile()
try {
   // tie up a resource
   writeMyFile(theData)
}
finally {
   closeMyFile() // always close the resource
}

嵌套

try 可以嵌套,当内部 try 没有对应的 catch,则抛出的错误被最近且有定义 catch 的上层所捕获。

执行顺序

throw

try {
    console.log(1)
    throw new Error('err')
} finally {
    console.log(2)
}

// 由于未定义 catch,抛出的错误会导致中断整体代码的运行
// 另外,这里的输出是:1 2 Error。至于 finally 为何先于 try 抛出的 Error,目前笔者没有深入考究。

假如以上代码块的 finally 也抛出错误,即如下:

try {
    console.log(1)
    throw new Error('a')
} finally {
    throw new Error('b')
    console.log(2)
}

// 那么输出 1 Error('b')。即 finally 里抛出的错误已经导致整体流程的中断(或取代了 Error('a'))。

return

在 try 中加入 return 语句
function test () {
  try {
    console.log(1);
    return 'from_try';
  } catch (e) {
    // TODO
  } finally {
    console.log(2);
  }
}

console.log(test()); // 1 2 from_try

从以上输出结果可看出,return 与上一小节 throw 情况类似,即 finally 优先于 trythrowreturn

在 finally 也加入 return 语句
function test () {
  try {
    console.log(1)
    return 'from_try'
  } catch (e) {
    // TODO
  } finally {
    console.log(2)
    return 'from_finally'
  }
}

console.log(test()); // 1 2 from_finally

同上,与上一小节 throw 情况类似,finally 的 return 优先于(或取代了) tryreturn(上一小节是 throw)。

在 try 语句里抛出错误
function test () {
  try {
    console.log(1);
    throw new Error('from_try')
  } catch (e) {
    console.log(e.message)
    return 'from_catch'
  } finally {
    console.log(2)
  }
}

console.log(test()) // 1 from_try 2 from_catch

从以上结果可看出,trycatchreturn 都需要先经过 finally,与 throw 类似。

return 改为 throw 进行验证:

function test () {
  try {
    console.log(1)
    throw new Error('from_try')
  } catch (e) {
    console.log(e.message)
    throw new Error('from_catch')
  } finally {
    console.log(2)
  }
}
test() // 1 from_try 2 from_catch

可见,throwreturn 对代码执行流程的控制是一样的。

参考