多级异步代码中的 Dart 错误
Dart Errors in multi-level asynchronous code
考虑以下代码
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()
是异步的,而是编写了以下内容(注意缺少的 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()
立即 returning,然后稍后,在另一个上下文中,doSomethingElse()
抛出错误,立即停止所有执行。我知道这个问题的答案可能是 "Well, don't do that then." 但我正在考虑我可能无法控制我正在调用的方法的情况(比如它们是否是库的一部分)。
这种情况会引出几个相关的问题:
- 作为
main()
的作者,有什么方法可以确保我对 doSomething()
的调用不会以未处理的异常结束?还是我依赖 doSomething()
的作者来确保所有可能的异常都得到处理或传播到 returned Future?有没有办法附加某种全局错误处理程序来捕获来自废弃 Futures 的错误?
- 作为
doSomething()
的作者,如果我不想等待 doSomethingElse()
(比如说它写入日志,那么我既不需要输出也不需要担心处理错误)。我能做些什么来防止 doSomethingElse()
中的错误停止程序,而不是将它的每次调用包装成一个 try/catch 块(这可能很麻烦,很容易被忽视)?
- 作为
doSomethingElse()
的作者,是否有一些我可以使用的模式允许我抛出异常,等待 Future 完成的调用者可以自己处理该异常,而没有调用者不等待 Future 不必担心捕获异常?在这方面,我最好的想法是 return 一个特殊对象而不是抛出异常,但这会增加很多额外的麻烦并使该方法更难使用。
注意:我在这里使用 async/await 语法,但这个问题应该与更严格的基于 Future 的构造同样相关(你 return 在 doSomething()
中的新 Future而不是 .then()
从 doSomethingElse()
中删除那个
喜欢 you can use Zones 以捕获异步代码中的意外错误。
未捕获的异步错误被处理到当前区域的错误处理程序。
您看到的是根区域的错误处理程序将错误报告为未捕获,这也终止了隔离。
您想要的是为您的代码引入不同的错误处理程序,通过 运行 通过 runZoned
错误处理程序:
import "dart:async";
main() {
runZoned(() async {
try {
print("trying");
await doSomething();
print("success");
} catch (e) {
print("caught");
}
}, onError: (e, s) {
print("uncaught");
});
}
考虑以下代码
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()
是异步的,而是编写了以下内容(注意缺少的 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()
立即 returning,然后稍后,在另一个上下文中,doSomethingElse()
抛出错误,立即停止所有执行。我知道这个问题的答案可能是 "Well, don't do that then." 但我正在考虑我可能无法控制我正在调用的方法的情况(比如它们是否是库的一部分)。
这种情况会引出几个相关的问题:
- 作为
main()
的作者,有什么方法可以确保我对doSomething()
的调用不会以未处理的异常结束?还是我依赖doSomething()
的作者来确保所有可能的异常都得到处理或传播到 returned Future?有没有办法附加某种全局错误处理程序来捕获来自废弃 Futures 的错误? - 作为
doSomething()
的作者,如果我不想等待doSomethingElse()
(比如说它写入日志,那么我既不需要输出也不需要担心处理错误)。我能做些什么来防止doSomethingElse()
中的错误停止程序,而不是将它的每次调用包装成一个 try/catch 块(这可能很麻烦,很容易被忽视)? - 作为
doSomethingElse()
的作者,是否有一些我可以使用的模式允许我抛出异常,等待 Future 完成的调用者可以自己处理该异常,而没有调用者不等待 Future 不必担心捕获异常?在这方面,我最好的想法是 return 一个特殊对象而不是抛出异常,但这会增加很多额外的麻烦并使该方法更难使用。
注意:我在这里使用 async/await 语法,但这个问题应该与更严格的基于 Future 的构造同样相关(你 return 在 doSomething()
中的新 Future而不是 .then()
从 doSomethingElse()
喜欢
未捕获的异步错误被处理到当前区域的错误处理程序。 您看到的是根区域的错误处理程序将错误报告为未捕获,这也终止了隔离。
您想要的是为您的代码引入不同的错误处理程序,通过 运行 通过 runZoned
错误处理程序:
import "dart:async";
main() {
runZoned(() async {
try {
print("trying");
await doSomething();
print("success");
} catch (e) {
print("caught");
}
}, onError: (e, s) {
print("uncaught");
});
}