【问题标题】:Create a new stream from a stream in Dart从 Dart 中的流创建一个新流
【发布时间】:2019-04-07 20:09:39
【问题描述】:

我怀疑我对 Dart 中 Streams 的理解可能有一些漏洞......

我有一种情况,我希望 Dart 应用程序响应间歇性输入(这会立即建议使用 Streamss 或 Futures,也许)。我可以使用 listener 函数实现我想要的行为,但我想知道如何以更好、更 Dartesque 的方式来实现。

作为一个简单的例子,下面的(工作的)程序监听来自用户的键盘输入,并在文档中添加一个 div 元素,该元素包含从前一个空格开始输入的内容,只要按下空格键。

import  'dart:html';

main() {
  listenForSpaces(showInput);
}

void  listenForSpaces(void  Function(String) listener) {
  var input =  List<String>();
  document.onKeyDown.listen((keyboardEvent) {
    var key = keyboardEvent.key;
    if (key ==  " ") {
      listener(input.join());
      input.clear();
    } else {
      input.add(key.length >  1  ?  "[$key]"  : key);
    }
  });
}

void  showInput(String message) {
  document.body.children.add(DivElement()..text = message);
}

我想做的是从我正在收听的Stream 创建一个新的Stream(在上面的示例中,从onKeyDown 创建一个新的Stream) .换句话说,我可以将上面的程序设置为:

var myStream = ...
myStream.listen(showInput);

我怀疑有一种方法可以创建Stream,然后在不同的时间和地点向其中插入元素或调用它来发出值:感觉好像我错过了一些简单的东西。无论如何,我们将不胜感激对文档的任何帮助或指导。

【问题讨论】:

    标签: stream dart future


    【解决方案1】:

    使用async* 函数从现有流创建新流相当容易。 对于正常的流,我会这样做:

    Stream<String> listenForSpaces() async* {
      var input = <String>[];
      await for (var keyboardEvent in document.onKeyDown) {
        var key = keyboardEvent.key;
        if (key == " ") {
          yield input.join();
          input.clear();
        } else {
          input.add(key.length > 1 ? "[$key]" : key);
        }
      }
    }
    

    async* 函数将暂停传播到底层流,它可能会在yield 期间暂停源。 这可能是也可能不是您想要的,因为暂停 DOM 事件流可能会导致您错过事件。对于 DOM 流,我可能更喜欢使用上面基于 StreamController 的解决方案。

    【讨论】:

      【解决方案2】:

      有几种方法,还有一个完整的包rxdart可以允许各种事情。

      只有最终消费者才应该使用listen,并且只有在您需要明确想要取消订阅时,否则使用forEach

      如果您想像示例中那样操作事件,请使用map

      【讨论】:

      • 赞成将我指向 rxdart。不过,我仍然坚持要一个明确的答案! :)
      • 不确定您希望得到明确答案的问题是什么。
      【解决方案3】:

      我最初并不打算回答我自己的问题,但后来我在dartlang creating streams 文章中找到了这个问题的一个非常简单的答案;如果它对其他人有帮助:

      具体来说,如果我们想创建一个流,我们可以在代码中的任意时间和位置插入元素,我们可以通过StreamController 类来实现。这个类的实例有一个add 方法;我们可以简单地使用实例的stream 属性作为我们的流。

      例如,我的问题中的代码可以重写为:

      import 'dart:html';
      import 'dart:async';
      
      main() async {
        // The desired implementation stated in the question:
        var myStream = listenForSpaces();
        myStream.listen(showInput);
      }
      
      Stream<String> listenForSpaces() {
        // Use the StreamController class.
        var controller = StreamController<String>();
      
        var input = List<String>();
        document.onKeyDown.listen((keyboardEvent) {
          var key = keyboardEvent.key;
          if (key == " ") {
            // Add items to the controller's stream.
            controller.add(input.join());
            input.clear();
          } else {
            input.add(key.length > 1 ? "[$key]" : key);
          }
        });
      
        // Listen to the controller's stream.
        return controller.stream;
      }
      
      void showInput(String message) {
        document.body.children.add(DivElement()..text = message);
      }
      

      (如文章中所述,如果我们想像这样从头开始设置流,我们需要小心,因为没有什么可以阻止我们将项目插入到没有关联的活动订阅者的流中;插入在这种情况下,项目将被缓冲,这可能导致内存泄漏。)

      【讨论】:

        猜你喜欢
        • 2015-10-16
        • 1970-01-01
        • 1970-01-01
        • 2015-09-23
        • 1970-01-01
        • 1970-01-01
        • 2019-12-06
        • 1970-01-01
        相关资源
        最近更新 更多