我是Dart dshell软件包的作者。
https://pub.dev/packages/dshell
Dshell是用于编写dart cli脚本的库和工具。
Dshell使用waitFor对用户隐藏期货,因为它们在典型的cli应用程序中几乎没有用。
我的问题是,如果future在由waitFor处理时抛出未处理的异常,则实际上会关闭应用程序。
我需要能够捕获任何异常,然后让调用者决定如何处理该异常。
这是到目前为止我尝试过的。没有任何catch技术将捕获未处理的异常:
import 'dart:async';
import 'dart:cli';
void main() {
var future = throwException();
try {
future
.catchError((Object e, StackTrace st) => print('onErrr: $e'))
.whenComplete(() => print('future completed'));
print(waitFor<int>(future));
} // on AsyncError
catch (e) {
if (e.error is Exception) {
print(e.error);
} else if (e is AsyncError) {
print('Rethrowing a non DShellException ${e}');
rethrow;
} else {
print('Rethrowing a non DShellException ${e}');
rethrow;
}
} finally {
print('waitForEx finally');
}
}
Future<int> throwException() {
var complete = Completer<int>();
Future.delayed(Duration(seconds: 2), () => throw Exception());
return complete.future;
}
dart waitFor的一行使我认为这可能是不可能的:
如果Future正常完成,则返回其结果。如果Future以错误完成,则错误和堆栈跟踪将包装在AsyncError中并引发。如果在此调用期间运行的微任务或消息处理程序导致未处理的异常,则该异常将被传播,就好像微任务或消息处理程序是堆栈上唯一的Dart调用一样。也就是说,微任务或消息处理程序中未处理的异常将跳过对waitFor的调用中暂停的堆栈。
所以我对'以错误完成的未来'和'微任务...导致未处理的异常'之间的区别感到困惑。
Future
返回的throwException
永远不会以值或错误完成。 Future.delayed
引发的错误是未处理的异步错误,它与从该方法返回的Future
完全无关。获得带有错误的Future的方法是:
Future.error
构造函数。Completer.completeError
上使用Completer
。throw
方法使用async
。throw
构造函数或Future
的回调中使用.then
。>因此在您的示例中,Future.delayed
创建了一个Future
,由于回调中的throw
,该错误将完成。没有人在听这个未来。没有await
,没有链接的.then
或.catchError
。一旦Future完成并出现错误,并且没有该错误的处理程序,它将冒泡到周围的错误区域。参见https://dart.dev/articles/archive/zones#handling-asynchronous-errors
如果您想对未处理的错误做出反应,可以使用runZoned
-正确获取详细信息可能很棘手。请注意,运行一些代码可能会导致多个未处理的异步错误,并且Future的完成并不一定意味着以后不会出现其他未处理的异步错误。
从内特·博世(Nate Bosch),我想出了一个可能的答案: