我正在设计一个API,希望处理用户错误地标记void
函数async
的情况。
简化代码如下所示:
void test(void Function() run) {
try {
for (var i = 0; i < 3; i++) {
print(i);
run();
}
} catch (e) {
print(e);
} finally {
print('in finally block.');
}
}
void errorThrower(String message) {
print('in errorThrower ');
throw message;
}
void main(List<String> args) {
test(() async{ // <-------- marked async by API user's mistake
print('in run ...');
errorThrower('error thrown in test');
});
}
如果函数被not标记为async
,则程序输出与预期的一样,错误被抛出,捕获,处理,并执行finally
块:
$ dart main.dart
0
in run ...
in errorThrower
error thrown in test
in finally block.
但是,如果函数标记为async
,则控制台输出为:
$ dart main.dart
0
in run ...
in errorThrower
1
in run ...
in errorThrower
2
in run ...
in errorThrower
in finally block.
Unhandled exception:
error thrown in test
#0 errorThrower (file:///home/dan/WORK/DartProjects/benchmark_runner/bin/throws_test.dart:16:3)
#1 main.<anonymous closure> (file:///main.dart:22:5)
#2 test (file:///main.dart:5:10)
#3 main (file:///main.dart:20:3)
#4 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:294:33)
#5 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:189:12)
这是怎么回事?我尝试了一个调试器,程序进入run()
,然后errorThrower
,然后循环继续。它看起来像一个未等待的未来错误,但我不知道如何捕获和处理它,因为void
函数不能等待。
有没有什么方法可以在不改变run()
签名的情况下捕获和处理错误?
2条答案
按热度按时间cngwdvgl1#
这是怎么回事?
标记为
async
的函数会自动转换,以便将返回值和抛出的对象 Package 在Future
s中。失败的Future
s必须通过向Future.catchError
注册回调来处理,通过在try
块内的Future
上使用usingawait
(这是注册Future.catchError
回调的语法糖),或者通过设置Zone
错误处理程序(我认为这超出了这个答案的范围)。从概念上讲,您可以将失败的Future
视为在 synchronoustest
函数已经离开其try
-catch
块之后从Dart事件循环中抛出异常。有没有什么方法可以在不改变
run()
签名的情况下捕获和处理错误?A
T Function()
is a subtype of (is substitutable for)void Function()
。因此,在编译时,您无法阻止Future<void> Function()
传递到需要void Function()
的位置。这也是为什么像Iterable.forEach
这样的东西不能阻止异步回调(even though it's almost always a bad idea)和would need support from the linter。您可以添加运行时检查:
或者,如果你只是想吞下错误:
请注意,如果您希望
test
等待run
完成(无论成功与否),那么test
本身将需要异步,并且需要返回Future
。在这一点上,你也可以总是假设run
可能是异步的,并且无条件地await
它:monwx1rj2#
看,我可以解释你的预期结果和实际结果的差异。
当你将一个函数标记为
async
时,这意味着该函数返回一个特殊类型的对象,称为Future
。Future
表示可能完成或未完成的潜在asynchronous
操作。当你调用一个async
函数时,它会立即返回,函数内部的工作发生在background
中。这就是使Dart能够执行asynchronous programming
的原因。在
test
函数中,您将另一个名为run的函数作为参数。当你将run标记为async
时,这意味着它返回一个Future<void>
,当你调用它without await
时,函数的执行不会暂停以等待run函数完成。相反,它立即使用循环continues
。这就是为什么您看到循环在运行,而无需等待run函数完成。它是并发运行的,它抛出的
exceptions
不会被try/catch
块捕获,因为在run函数完成之前,try/catch
块已经完成。下面的代码将导致您预期的答案:
现在,想想它是如何给予预期的结果!如果你没有得到答复。