Создать новый поток из потока в Dart - PullRequest
0 голосов
/ 04 ноября 2018

Я подозреваю, что в моем понимании Stream s в Dart могут быть несколько дыр ...

У меня есть ситуация, в которой я хотел бы, чтобы приложение Dart реагировало на прерывистый ввод (что сразу же предполагает использование Streams с - или Future с, возможно). Я могу реализовать желаемое поведение с помощью listener функций, но мне было интересно, как это сделать лучше, более Dart esque .

В качестве простого примера следующая (рабочая) программа прослушивает ввод с клавиатуры пользователем и добавляет элемент 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, который я слушаю (в приведенном выше примере, создать новый Stream из onKeyDown) , Другими словами, я мог бы изложить программу выше как:

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

Я подозреваю, что есть способ создать Stream, а затем, в разное время и в разных местах, вставлять в него элементы или призывать его выдавать значение: мне кажется, что я упускаю что-то простое. В любом случае, любая помощь или направление к документации будут оценены.

Ответы [ 3 ]

0 голосов
/ 05 ноября 2018

Изначально я не планировал отвечать на свой вопрос, но с тех пор я нашел очень простой ответ на этот вопрос в статье dartlang создавая потоки ; в случае, если это полезно для других:

В частности, если мы хотим создать поток, в который мы можем вставлять элементы в произвольные моменты времени и места в коде, мы можем сделать это с помощью класса 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);
}

(Как уже упоминалось в статье, мы должны быть осторожны, если мы хотим настроить поток с нуля, как это, потому что ничто не мешает нам вставлять элементы в потоки, которые не имеют связанных активных подписчиков; вставлены в этом случае элементы будут буферизованы, что может привести к утечке памяти.)

0 голосов
/ 05 ноября 2018

Создать новый поток из существующего потока довольно просто с помощью функции 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.

0 голосов
/ 04 ноября 2018

Есть несколько методов, и есть целый пакет rxdart, чтобы разрешить все виды вещей.

Только конечный потребитель должен использовать listen, и только если вам необходимо явно отказаться от подписки, в противном случае используйте forEach

Если вы хотите манипулировать событиями, как в вашем примере, используйте map.

...