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

时间:2019-10-11 06:08:30

标签: 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");
}
  

使用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");
}
  

使用onError

     

错误1

runZoned()上的那些异步方法会彻底改变行为,应该这样做吗?

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

2 个答案:

答案 0 :(得分:2)

您正在触及期货和错误(处理)区域的尖锐边缘。

在一个错误区域中引发的错误不会传播到将来在另一个错误区域中创建的错误处理程序。 因此,如果您从另一个错误区域获得了未来,并且已经完成了一个错误,那么您将无法获得错误,也就没有价值可取,因此未来将看起来像 never < / em>完成。

代码

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");
}

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

然后,runZoned完成时,它将返回该将来,并在与调用不同的错误区域中创建错误。它await(在根区域,这是一个不同的错误区域)进行了编辑,因此await runZoned(() async { ... }, ...) 永远不会完成await等待将来完成,将来拒绝将完成的错误提供给侦听器,因此什么也没发生。

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

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

第一个示例之所以有效,是因为您正在同步抛出而不返回将来。立即捕获同步引发,然后runZoned返回null。 (不过,当Dart获取非空类型时,这将不得不更改。)

通常,使用runZoned处理程序返回可能包含来自onError的错误的期货可能不是一个好主意。我们无法避免这种情况(返回Object很好,而期货是对象),但是应该记录在案。

答案 1 :(得分:0)

感谢Irn的答案,我理解并使用Completer来实现自己的目标:

main(args) async {
  var completer = Completer();
  await runZoned(() {
    Future.microtask((){
      throw Future.error(false);
    });
    completer.complete();
  }, onError: (e) {
    // ...
    completer.complete();
  });
  print("finish");
}