# Streams — Dart

Source: https://www.skillbyai.com/en/dart/a-streams

> Consume and create streams of asynchronous events.

## Many values over time

A **`Stream<T>`** delivers a sequence of asynchronous events: user input, WebSocket messages, file chunks, database change notifications, location updates. Consume a stream with **`await for`** inside an `async` function, or with **`listen`**, which returns a `StreamSubscription` you can pause, resume and **cancel** (always cancel subscriptions you no longer need to avoid leaks, for example in a Flutter widget's `dispose`). **Single-subscription** streams (the default, such as reading a file) allow one listener; **broadcast** streams allow many listeners and suit events such as UI notifications. Streams have collection-like operators: `map`, `where`, `take`, `skip`, `distinct`, `asyncMap`, `expand` and `handleError`. Create streams with **`async*`** generator functions that `yield` values, or with a **`StreamController`** that you add events to, close when finished, and expose via its `stream` property. Packages such as `rxdart` add more operators, and Flutter's `StreamBuilder` rebuilds widgets as events arrive.

## A stream generator, a controller and await for

async* yields values over time; controllers bridge callback code.

```dart
import 'dart:async';

Stream<int> countdown(int from) async* {
  for (var i = from; i >= 0; i--) {
    await Future<void>.delayed(const Duration(seconds: 1));
    yield i;                                 // emit the next value
  }
}

class CartEvents {
  final _controller = StreamController<String>.broadcast();
  Stream<String> get stream => _controller.stream;

  void itemAdded(String sku) => _controller.add('added $sku');
  Future<void> dispose() => _controller.close();
}

Future<void> main() async {
  await for (final seconds in countdown(3)) {
    print('Sale starts in $seconds');
  }

  final events = CartEvents();
  final subscription = events.stream
      .where((e) => e.startsWith('added'))
      .listen((e) => print('Event: $e'));

  events.itemAdded('pen');
  events.itemAdded('ink');
  await Future<void>.delayed(Duration.zero);   // let events be delivered
  await subscription.cancel();                  // always cancel when done
  await events.dispose();
}
```

## A newspaper subscription

A Future is a single parcel you are waiting for. A Stream is a newspaper subscription: issues keep arriving until the publisher stops, and you should cancel the subscription when you move away.

**Quiz:** What does an async* function return?

- [ ] A Future
- [x] A Stream, emitting values with yield
- [ ] A List
- [ ] An Isolate

*Answer:* A Stream, emitting values with yield. async* generators produce streams; sync* generators produce iterables.
