Dart 在异步修改体上的 runZoned() 行为

Nic*_*ich 1 asynchronous dart

我不明白这种行为......

main(args) async {
  await runZoned(() {
    throw false;
  }, onError: (e) async {
    print("working in onError");
    await runZoned(() {
      throw false;
    }, onError: (e) async {
      print("error 1");
    });
    print("error 2");
  });
  print("finish");
}
Run Code Online (Sandbox Code Playgroud)

在 onError 中工作

错误 1

错误 2

结束

main(args) async {
  await runZoned(() async {
    throw await Future.error(false);
  }, onError: (e) async {
    print("working in onError");
    await await runZoned(() async {
      throw await Future.error(false);
    }, onError: (e) async {
      print("error 1");
    });
    print("error 2");
  });
  print("finish");
}
Run Code Online (Sandbox Code Playgroud)

在 onError 中工作

错误 1

runZoned() 上的异步从根本上改变了行为,他们应该这样做吗?

我需要那些异步并达到print("finish")始终。我该如何解决这个问题?

lrn*_*lrn 5

您正处于期货和错误(处理)区域的锐利边缘。

在一个错误区域中抛出的错误不会传播到在另一个错误区域中创建的未来错误处理程序。所以,如果你从不同的错误区域得到一个未来,并且它以错误完成,那么你就无法得到错误,并且没有价值可以得到,所以未来看起来永远不会完成。

编码

main(args) async {
  await runZoned(() async {
    await Future.error(false);
  }, onError: (e) async {
    print("working in onError");
    await runZoned(() async {
      await Future.error(false);
    }, onError: (e) async {
      print("error 1");
    });
    print("error 2");
  });
  print("finish");
}
Run Code Online (Sandbox Code Playgroud)

runZone在新的错误区域中运行参数。它们是返回期货的异步函数,因此await Future.error(false)将在该特定错误区域抛出并完成返回的期货并出现错误。

然后,当runZoned完成时,它返回那个未来,并在与调用不同的错误区域中创建一个错误。它是awaited (在根区,这是一个不同的错误区)所以await runZoned(() async { ... }, ...) 永远不会完成。在await为将来完全等待,未来拒绝给它与给听者完成了错误,所以什么也没发生。

实际上,您正在等待一个永远不会完成的未来,这就是您的程序在那一刻停止的原因。

所以这是按预期工作的 - 错误永远不会离开它创建的错误区域,但是离开外部区域没有任何结果。

第一个示例有效,因为您是同步抛出,而不是返回未来。同步 throw 立即被捕获,然后runZoned返回null。(不过,当 Dart 获得不可为空的类型时,这将不得不改变)。

一般来说,runZoned使用onError处理程序返回可能包含错误的期货可能是一个坏主意。我们无法阻止这种情况(返回Object很好,期货是对象),但也许应该记录下来。