掘金 阅读 ( ) • 2024-03-27 14:14

try-catch 原理

try-catch 是一种异常处理机制,用于捕获和处理代码中可能抛出的异常。

  • 当程序执行到 try 块时,会按照顺序执行其中的代码;
  • 如果 try 块中的代码执行异常,程序会立即跳转到与 catch 关键字对应的 catch 块中执行;
  • 在 catch 块中,可以对异常进行捕获和处理,比如打印错误信息、记录日志、或者进行一些恢复性操作;
  • 如果 catch 块中的代码执行完毕,程序会继续执行 try-catch 块之后的代码;

image.png

Future 原理

Future 是 Dart 中用于处理异步操作的关键字之一。当调用一个异步函数时,该函数会立即返回一个 Future 对象,表示异步操作的结果,异步对象可能是一个值,也可能是一个异常。Future 的主要使用场景包括:

  1. 异步操作的结果表示:当需要执行一个耗时的操作,例如从网络获取数据、文件读写操作等,而不想阻塞当前线程时,就可以使用 Future 来表示这个异步操作的结果。通过 Future,我们可以在异步操作完成后获取到操作的结果,或者在操作失败时获取到错误信息。

  2. 异步操作的串行化和并行化:通过 Future,我们可以将多个异步操作串行化或并行化执行,从而提高程序的性能和响应速度。例如,使用 Future.then() 方法可以在一个异步操作完成后执行另一个异步操作,或者使用 Future.wait() 方法可以等待多个异步操作全部完成后再进行下一步操作。

  3. 异常处理Future 也提供了异常处理的功能。当一个异步操作失败时,可以通过 catchError() 方法或 try-catch 块来捕获异常,并进行相应的处理。

Future 的原理主要是基于事件循环和回调机制。当一个异步操作被调用时,它会立即返回一个 Future 对象,表示该操作的结果。然后,异步操作会在后台执行,而不会阻塞当前线程。当操作完成时,会通知事件循环,并将操作的结果传递给对应的 Future 对象。这时,可以通过 Future 对象的方法来获取操作的结果或处理可能发生的异常。

总的来说,Future 关键字提供了一种便捷的方式来处理异步操作,使得程序可以更加高效地利用资源,并提高用户体验。

void main() async {
    Future<dynamic> catchMethodA(Function executionMethod) async {
      return await executionMethod();
    }

    Future<dynamic> catchMethodB() async {
      print("catchMethodB executioned");
      throw Exception("catchMethodB Error");
    }

    try {
      var methodAResult = await catchMethodA(() {
        try {
          return catchMethodB();
        } catch (e) {
          print("catch a exception in catchMethodB");
        }
      });
      print("methodAResult=$methodAResult");
    } catch (e) {
      print("catch a exception in catchMethodA, it's main method");
    }

}

提问: 1、执行结果应该是什么 2、为什么

image.png

print:

catchMethodB executioned
catch a exception in catchMethodA, it's main method

为什么:

内部函数catchMethodB执行前没有使用 await 进行同步处理,并不会等待异步操作完成,执行它将会立即返回一个 Future<dynamic> 对象。在这种情况下,第一次捕获的将是一个 Future<dynamic> 对象,而不是实际的异常。

这意味着外部 methodAResult 捕获的是一个未完成的 Future 对象,其结果值为异常。外部的 try-catch 块通过 await 关键字等待这个 Future 对象的完成,当异步操作完成后,该 Future 对象的状态将变为已完成,并且携带着异常的信息。捕获到了其中携带的异常信息。

让我们逐步分析这段代码的执行过程:

  1. main 函数开始执行。
  2. catchMethodA 函数被调用,传入一个匿名函数作为参数。
  3. catchMethodA 函数内部执行传入的匿名函数,即执行以下代码:
    try {
        return catchMethodB();
    } catch (e) {
        print("catch a exception in catchMethodB");
    }
    
  4. 在匿名函数内部,catchMethodB 函数被调用。
  5. catchMethodB 函数内部执行,并打印一条信息。
  6. catchMethodB 函数抛出一个异常 Exception("catchMethodB Error")
  7. Exception("catchMethodB Error")Future<dynamic> 对象返回给methodAResult
  8. catchMethodA 函数接收到异常的 Future 对象,并立即返回给 main 函数。
  9. main 函数中的 try-catch 块捕获到异常的 Future 对象,并执行 catch 块中的代码,打印一条信息 "catch a exception in catchMethodA, it's main method"

因此,main 函数的执行结果是打印如下信息:

catchMethodB executioned
catch a exception in catchMethodA, it's main method

在给定的代码中,"catch a exception in catchMethodB" 没有被打印出来,这是因为异常并没有在 catchMethodB 函数内部被捕获。让我们仔细分析一下原因:

  1. catchMethodB 函数内部没有显式的 try-catch 块来捕获可能抛出的异常;
  2. 异常在 catchMethodB 函数内部抛出后, 以 Future<dynamic>返回会沿着调用栈向上层传播,直到找到一个可以捕获异常的 try-catch 块或直到程序终止;

因此,即使异常是在 catchMethodB 函数内部抛出,但实际上异常的处理是 main 进行的,所以 "catch a exception in catchMethodB" 没有被打印出来。