【问题标题】:Yield values from generator from async functions without awaiting无需等待即可从异步函数生成生成器的值
【发布时间】:2021-06-05 12:32:19
【问题描述】:

我需要同时运行许多异步函数并在它们完成时产生结果,顺序无关紧要。

这是我在一个简化示例中的内容,当然这不起作用,因为它在移动到下一个请求之前等待每个响应。

 Stream<String> stringGenerator(List<http.Request> requests) async* {
    final httpClient = http.Client();
    for (var req in requests) {
      final response = await httpClient.send(req);
      yield response.headers['example'];
    }
  }

【问题讨论】:

    标签: dart generator dart-async dart-stream


    【解决方案1】:

    你能试试看这是否适合你吗?

    Stream<String> stringGenerator(List<http.Request> requests) {
      final controller = StreamController<String>();
      final httpClient = http.Client();
    
      Future.wait(requests.map((req) => httpClient
              .send(req)
              .then((response) => controller.add(response.headers['example']!))))
          .whenComplete(() => controller.close());
    
      return controller.stream;
    }
    

    更正确的是这样,因为我们不想在根据StreamController 的文档侦听事件之前生成事件。内部使用确实不是问题,因为 StreamController 会缓冲事件,直到订阅了侦听器:

    Stream<String> stringGenerator(List<http.Request> requests) {
      final controller = StreamController<String>();
      
      controller.onListen = () {
        final httpClient = http.Client();
    
        Future.wait(requests.map((req) => httpClient
            .send(req)
            .then((response) => controller.add(response.headers['example']!))))
            .whenComplete(() => controller.close());
      };
    
      return controller.stream;
    }
    

    【讨论】:

      【解决方案2】:

      @julemand101 解决方案的通用替代方案,适用于任何类型的期货:

      Stream<T> fromFutures<T>(Iterable<Future<T>> futures) {
        var pending = 0;
        var controller = Controller<T>();
        for (var future in futures) {
          pending++;
          future.then((v) {
            controller.add(v);
            if (--pending == 0) controller.close();
          }, onError: (e, s) {
            controller.addError(e, s);
            if (--pending == 0) controller.close();
          });
        }
        return controller.stream;
      }
      

      你可以使用这个指定stringGenerator

      Stream<String> stringGenerator(List<http.Request> requests) async* {
        var client = http.Client();
        yield* fromFutures(requests.map(client.send));
      }
      

      【讨论】:

        猜你喜欢
        • 2017-05-25
        • 2021-07-04
        • 2019-06-16
        • 1970-01-01
        • 1970-01-01
        • 2018-02-13
        • 2013-09-16
        • 2019-08-17
        • 2020-01-10
        相关资源
        最近更新 更多