【发布时间】: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