在 Dart 中,如何确保流更新在继续之前完成?

Posted

技术标签:

【中文标题】在 Dart 中,如何确保流更新在继续之前完成?【英文标题】:In Dart, how to ensure stream updates are finished before moving on? 【发布时间】:2019-06-13 09:03:42 【问题描述】:

我在 Dart 2.1.0 中编程,尝试通过监听自定义流来更新一些状态:

import 'dart:async';

void main() 
  final controller = StreamController<int>();
  final divisibleBy2 = controller.stream.map((i) => i % 2 == 0);

  var seen2x = false;
  divisibleBy2.listen((y) 
    seen2x = y;
  );

  controller.add(2);
  print(seen2x);

当我运行它时,它会打印出false。显然,print 函数比侦听器函数调用得更早。状态没有及时更新。

通过await-ing controller.add(2),我可以直接得到订单:

import 'dart:async';

void main() async 
  final controller = StreamController<int>();
  final divisibleBy2 = controller.stream.map((i) => i % 2 == 0);

  var seen2x = false;
  divisibleBy2.listen((y) 
    seen2x = y;
  );

  await controller.add(2);
  print(seen2x);

现在它打印true。监听函数在print之前被调用。

但是为什么await 在这种情况下会有所作为? StreamController's add() method 返回一个 Future,所以我不确定为什么 await 很重要。事实上,在我的流网络变得更加复杂的实际使用中,await 有时不足以确保执行顺序。这是另一天的问题。

现在,我只想看看await 是否是正确的做法。提前致谢。

【问题讨论】:

StreamController构造函数中使用sync参数 抱歉回复晚了。我确实尝试过,并且不愿意使用它。根据docs,使用同步 StreamController 有很多注意事项,因为它“可用于打破 Stream 上的合同”。在我的测试中,它确实会导致一些奇怪的、意想不到的行为。 最后,我意识到像我在流旁边所做的那样改变状态确实不是解决问题的正确方法。我修改了流网络以在最后吐出新状态,而不是在中间改变状态。现在一切正常。 好,您最初的“订购”要求一开始听起来很奇怪;-) 【参考方案1】:

await 在这里有所不同的原因是 any await 将至少等待一个微任务 - 无论您等待的值是否为 Future。如果它是Future,它将等待它完成,如果它已经完成,它将等待一个微任务。如果您在controller.add(2); 之后有await null;,它的行为将相同。

一般来说,StreamController 不知道所有侦听器何时都收到了事件,尤其是考虑到异步侦听器或Stream.asyncMap 之类的事情。

【讨论】:

【参考方案2】:

我将为我在等待流完成时所做的事情添加一个替代答案。 await for 是我要找的钥匙。

var myStream = CustomCacheManager().getFile(_url);
File fetchedFile;
await for (var fileInfo in myStream) 
  fetchedFile = fileInfo.file;


// stream is finished now

【讨论】:

以上是关于在 Dart 中,如何确保流更新在继续之前完成?的主要内容,如果未能解决你的问题,请参考以下文章

在 openMP 中,如何确保线程在继续之前同步?

在 Swift 中,如何在继续编写代码之前安全地确保从 Google 检索数据(日期和时间)?

如何确保 D3 在 javascript 运行之前完成加载多个 CSV?

理解 Dart 中的异步和同步

在解释响应之前,如何确保此功能完成?

如何确保在完成写入文件之前不读取文件