【问题标题】:Dart Errors in multi-level asynchronous code多级异步代码中的 Dart 错误
【发布时间】:2015-03-03 16:55:26
【问题描述】:

考虑下面的代码

import 'dart:async';

Future main() async {
  try {
    print("trying");
    await doSomething();
    print("success");
  } catch (e) {
    print("caught");
  }
}

Future<int> doSomething() async {
  await doSomethingElse();
  return 5;
}

Future<int> doSomethingElse() async {
  throw new Exception();
}

运行时,doSomethingElse() 中抛出的异常被main() 捕获,一切正常。但是,假设编写doSomething() 方法的人没有意识到doSomethingElse() 是异步的,而是编写了following(注意缺少await)。

Future<int> doSomething() async {
  doSomethingElse();
  return 5;
}

现在这个异常根本没有被捕获。相反,输出现在看起来像这样:

trying
success
Unhandled exception:
Uncaught Error: Exception
Stack Trace:
#0      doSomethingElse.<doSomethingElse_async_body> (file:///C:/code/test.dart:19:7)
#1      Future.Future.<anonymous closure> (dart:async/future.dart:118)
<snip>

发生的事情是doSomething() 立即返回,然后在稍后的某个时间,在另一个上下文中,doSomethingElse() 抛出错误,立即停止所有执行。我知道对此的回答可能是“好吧,那就不要那样做”。但我正在考虑我可能无法控制我正在调用的方法的情况(比如它们是否是库的一部分)。

这种情况导致了几个相关的问题:

  • 作为main() 的作者,有什么方法可以确定我对doSomething() 的调用不会以未处理的异常结束?还是我依赖​​doSomething() 的作者来确保所有可能的异常都得到处理或传播到返回的Future?有没有办法附加某种全局错误处理程序,可以从废弃的 Futures 中捕获错误?
  • 作为doSomething() 的作者,如果我不想等待doSomethingElse()(比如说它写入日志,所以我不需要输出,也不需要担心处理错误)。除了将每次调用都包装为 try/catch 块(这可能很麻烦且容易被忽视)之外,我还能做些什么来防止 doSomethingElse() 中的错误停止程序?
  • 作为doSomethingElse() 的作者,我是否可以使用某种模式来抛出异常,以便等待 Future 完成的调用者可以自己处理该异常,而不等待未来不必担心捕获异常?在这方面我最好的想法是返回一个特殊对象而不是抛出异常,但这会增加很多额外的麻烦并使该方法更难使用。

注意:我在这里使用 async/await 语法,但这个问题应该与更严格的基于 Future 的构造同样相关(在 doSomething() 中返回一个新的 Future 而不是 .then()doSomethingElse()

【问题讨论】:

  • 您可以使用zones 处理这些错误,并且计划添加一个隔离顶级错误处理程序,但我认为这还没有实现。
  • 正确实现的库中的函数或类方法将明确地是同步或异步的,只有真正需要异步的函数才如此——就像现在的库函数一样,如果它们是异步的,则返回 Future。我还没有使用过这种语法,但我认为编辑器在检测到等待/异步不匹配时会标记错误。

标签: asynchronous dart


【解决方案1】:

Greg pointed in its comment 一样,您可以使用Zones 从异步代码中捕获意外错误。

【讨论】:

    【解决方案2】:

    未捕获的异步错误由当前区域的错误处理程序处理。 您看到的是根区域的错误处理程序将错误报告为未捕获,这也终止了隔离。

    您想要为您的代码引入不同的错误处理程序,方法是使用错误处理程序通过runZoned 运行它:

    import "dart:async";
    main() {
      runZoned(() async {
        try {
          print("trying");
          await doSomething();
          print("success");
        } catch (e) {
          print("caught");
        }
      }, onError: (e, s) {
        print("uncaught");
      });
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-25
      • 1970-01-01
      • 2021-08-17
      • 1970-01-01
      • 2019-08-29
      • 1970-01-01
      相关资源
      最近更新 更多