Используйте классы Dart для работы с потоковыми данными
Концепция Streams оказалась сложной темой для понимания для большинства программистов, ныряющих в Dart (или любой другой язык в этом отношении), отчасти потому, что для понимания требуется пара попыток вместе с примерами. В этой статье я попытаюсь демистифицировать использование потоков в Dart, создавая что-то осязаемое с помощью того, что мы узнаем далее в этой серии.
Что такое потоки?
Глядя на документацию Dart, он определяется как:
Источник асинхронных событий данных. Stream предоставляет способ получить последовательность событий. Каждое событие является либо событием данных, также называемым элементом потока, либо событием ошибки, которое является уведомлением о том, что что-то не удалось. Когда поток передал все свои события, одно событие «готово» уведомит слушателя о том, что конец достигнут.
api.dartlang.org
Потоки как концепция относятся к каналу, по которому данные передаются из точки A в точку B. В этом канале мы можем выполнять различные преобразования данных, которые «считываются», прежде чем они достигнут точки. Б. Этот канал полезен при передаче данных фрагментами, а не целиком сразу.
Вы работаете с Streams в Dart с помощью набора вспомогательных классов, предлагаемых SDK. Эти вспомогательные классы предоставляют служебные методы для передачи данных в поток, а также уведомляют слушателей этого потока о необходимости захвата любых добавляемых данных.
Самый общий класс, представляющий поток, называется Stream<T>
. Обычно мы не используем этот класс напрямую, потому что он скорее предоставляется другими классами в арсенале Dart. Рассматривайте это как интерфейс для взаимодействия с этим каналом, по которому проходят данные.
Базовый пример с StreamController ‹T›
StreamController<T>
содержит поток, который позволяет потребителю отправлять ему данные, выполненные и ошибочные события. Мы могли бы получить доступ к этому потоку, выполнив streamController.stream
, что позволит нам вызывать любой из методов, определенных в его документации.
Вот пример с классом StreamController<T>
:
var streamController = StreamController(); // Accessing the stream and listening for data event streamController.stream.listen((data) { print('Got eem! $data'); });
Приведенный выше фрагмент позволяет нам отслеживать канал потока входящих блоков данных. Затем мы отвечаем на эти данные, выводя их на консоль.
Итак, я предполагаю, что следующий вопрос звучит так: Как мы запускаем событие прослушивателя данных? Ответ: путем подачи данных в поток! Это стало возможным благодаря другому классу под названием EventSink<T>
. Этот объект содержит add()
метод подачи данных в поток:
streamController.sink.add('Added this string'); // Result // Got eem! Added this string
Метод listen()
в потоке также может перехватывать сообщения об ошибках. Это потому, что объект StreamSubscription<T>
генерируется всякий раз, когда вы слушаете поток. Этот объект является причиной возможности обработки различных событий, таких как данные, ошибка и выполнение (когда в потоке вызывается метод close ()).
Вот полное определение метода listen()
:
StreamSubscription<T> listen ( void onData(T event), { Function onError, void onDone(), // Invoked when the stream is closed bool cancelOnError // Kills the stream when an error occurs });
Вот как бы мы назвали события «ошибка» и «готово»:
streamController.sink.addError('Houston, we have a problem!'); // Got an error! Houston, we have a problem! streamController.sink.close(); // Mission complete!
Потоки, предоставляемые через библиотеки
Хотя StreamController<T>
позволяет нам детально управлять потоками, которые мы создаем сами, существуют встроенные библиотеки дротиков, которые используют потоки под капотом. Например, взгляните на этот фрагмент для настройки сервера:
import 'dart:io'; void main() async { var server = await HttpServer.bind('localhost', 8080); // HttpServer exposes a Stream<T> interface server.listen((HttpRequest request) { request.response.write('Hello, World!'); request.response.close(); }); }
Приведенный выше фрагмент создает экземпляр HttpServer
для создания веб-серверов. Этот класс предоставляет интерфейс Stream<T>
, что означает, что теперь мы можем прослушивать этот поток, который будет содержать объекты запроса, созданные, когда пользователь обращается к нашему серверу.
Вот еще один пример потока, отображаемого в веб-браузере:
import 'dart:html'; void main() { var button = querySelector('button'); // `onClick` is a Stream<T> instance that receives user click data events button.onClick.listen((_) => print('Button clicked!')); }
Взаимодействия пользователя, происходящие в браузере, такие как щелчок, прокрутка, ввод и т. Д., Генерируются как события «данных», захваченные в потоке. Другими словами, элементы HTML также предоставляют Stream<T>
интерфейс для взаимодействия с пользователем на странице.
Существует гораздо больше классов, которые используют потоки под капотом, причем здесь дело в том, что, как правило, вы не будете создавать экземпляры Stream<T>
объектов напрямую, а скорее они будут созданы для вас с помощью различных библиотечных классов в SDK.
Заключение
Потоки предоставляют мощный способ работы с порциями данных. Поскольку это работает асинхронно, мы получаем преимущество выполнения кода в неблокирующем режиме. Я бы рекомендовал прочитать документацию, особенно библиотеку dart: async, которая содержит классы для асинхронного программирования, такие как Streams и Futures.
В следующей части серии мы рассмотрим, как выполнять преобразования в потоке, а также продемонстрируем общий шаблон проектирования, основанный на использовании потоков 🧱
продолжить чтение
→ Как использовать потоки в Dart (Часть 2)
дальнейшее чтение
Делиться заботой 🤗
Если вам понравилось читать этот пост, поделитесь им в различных социальных сетях. Также проверьте и подпишитесь на мой канал YouTube (нажмите на значок колокольчика) для видео на Dart.
Подпишитесь на мой информационный бюллетень, чтобы загрузить мою бесплатную электронную книгу Начало работы с Dart и получать уведомления о выходе нового содержания.
Ставьте лайки, делитесь и подписывайтесь на меня 😍, чтобы узнать больше о Dart.