【问题标题】:Difference between await for and listen in DartDart 中 await for 和 listen 的区别
【发布时间】:2017-07-25 12:16:36
【问题描述】:

我正在尝试创建一个 Web 服务器流。代码如下:

import 'dart:io';

main() async {
  HttpServer requestServer = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 8000);

requestServer.listen((request) {   //comment out this or the await for to work
  request.response
    ..write("This is a listen stream")
    ..close();
});

  await for (HttpRequest request in requestServer) {
  request.response
    ..write("This is an await for stream")
    ..close();
  }
}

监听和等待有什么区别?它们都不能同时工作。您需要注释掉其中一个才能工作,但这里的功能似乎没有区别。是否存在差异,什么时候应该使用其中的一种?

【问题讨论】:

    标签: stream async-await dart listen


    【解决方案1】:

    给定:

    Stream<String> stream = new Stream<String>.fromIterable(['mene', 'mene', 'tekel', 'parsin']);
    

    然后:

    print('BEFORE');
    stream.listen((s) { print(s); });
    print('AFTER');
    

    产量:

    BEFORE
    AFTER
    mene
    mene
    tekel
    parsin
    

    而:

    print('BEFORE');
    await for(String s in stream) { print(s); }
    print('AFTER');
    

    产量:

    BEFORE
    mene
    mene
    tekel
    parsin
    AFTER
    

    stream.listen() 设置当事件到达时将放入事件队列的代码,然后执行以下代码。

    await for 在事件之间暂停并一直这样做直到流完成,所以在它发生之前不会执行它后面的代码。

    当我有一个我知道会有有限事件的流并且我需要在做任何其他事情之前处理它们(基本上就像我正在处理一个期货列表一样)时,我使用 `await。

    查看https://www.dartlang.org/articles/language/beyond-async 以获取await for 的描述。

    【讨论】:

    • await for(var x in stream) ... 语法更接近于await stream.forEach((x) { ... }) 而不是listen,就像for (var x in iterable) ... 类似于iterable.forEach((x) { ... })。差异来自for 循环允许forEach 不允许的控制流。
    • 链接失效
    • 很好的解释!
    【解决方案2】:

    主要区别在于之后有代码。 listen 只注册处理程序并继续执行。 await for 将保持执行直到流关闭。

    因此,如果您在main 的末尾添加print('hello');,您不应该在await for 的输出中看到hello(因为请求流永远不会关闭)。 Try the following code on dartpad 看看差异:

    import 'dart:async';
    main() async {
      tenInts.listen((i) => print('int $i'));
      //await for (final i in tenInts) {
      //  print('int $i');
      //}
      print('hello');
    }
    Stream<int> get tenInts async* {
      for (int i = 1; i <= 10; i++) yield i;
    }
    

    【讨论】:

      【解决方案3】:

      一个更重要的区别是await for 将流项目的消费序列化,而listen 将同时处理它们。

      例如下面的代码:

      import 'dart:async';
      
      Future<void> process(int i) async {
        print("start $i");
        await new Future.delayed(const Duration(seconds: 1));
        print("end $i");
      }
      
      main() async {
        await for (final i in tenInts) {
          await process(i);
        }
        tenInts.listen((i) async => await process(i));
        print('hello');
      }
      Stream<int> get tenInts async* {
        for (int i = 1; i <= 10; i++) yield i;
      }
      

      产量

      start 1
      end 1
      start 2
      end 2
      start 3
      end 3
      start 4
      end 4
      start 5
      end 5
      start 6
      end 6
      start 7
      end 7
      start 8
      end 8
      start 9
      end 9
      start 10
      end 10
      hello
      start 1
      start 2
      start 3
      start 4
      start 5
      start 6
      start 7
      start 8
      start 9
      start 10
      end 1
      end 2
      end 3
      end 4
      end 5
      end 6
      end 7
      end 8
      end 9
      end 10
      

      【讨论】:

      • 这是一个非常重要的区别!这是我一直在寻找解决某个问题的方法,谢谢!
      • 最佳答案!
      【解决方案4】:

      另一个区别可能是listen() 返回一个StreamSubscription 对象,可用于在以后的任何时间点取消/暂停订阅。您可以设置为每个数据事件或错误事件以及流关闭时调用的回调。

      下图演示了在听流5秒后,我们将取消它。

      Stream<int> gen() async* {
        for (int i = 1; i <= 10; i++) {
          await Future.delayed(Duration(seconds: 1));
          yield i;
        }
        print("done");
      }
      
      main() async {
        Stream<int> stream = gen();
        var subscription = stream.listen((item){
          print(item);
        });
        
        await Future.delayed(Duration(seconds: 5));
        subscription.cancel();
        
        print("Exit");
      }
      
      Output:
      1
      2
      3
      4
      Exit
      

      【讨论】:

        【解决方案5】:

        正如罗布森所说:

        await 用于在监听时序列化流项的消费 将同时处理它们。

        我还想补充一点,如果使用 pause 和 resume 方法,则使用 listen 方法可以一一处理流事件。 应该在第一个 await 关键字之前调用暂停方法。

        StreamSubscription<int> subscription;
        subscription = tenInts.listen((i) async {
            subscription.pause();
            await process(i);
            subscription.resume();
          });
        
        Future<void> process(int i) async {
          print("start $i");
          await new Future.delayed(const Duration(seconds: 1));
          print("end $i");
        }
        

        【讨论】:

          猜你喜欢
          • 2016-04-14
          • 2021-02-23
          • 1970-01-01
          • 2017-03-04
          • 1970-01-01
          • 2013-12-22
          • 2017-02-12
          • 2015-01-21
          • 2016-09-29
          相关资源
          最近更新 更多