在 Dart 中有兩種異步類別,一種是 Future
,另一種則是 Stream
,在上一篇我們知道 Future
是針對耗時的工作,在工作完成時才回傳結果。並且可以利用 async
關鍵字建立異步函數,並在該函數使用await
關鍵字來等待 Future
的回傳值。
另一個異步類別為 Stream
Stream
?Stream 是用來接收一連串的事件,註冊 Stream 的 監聽器 (Listener) 之後,若 Stream 有事件,則將會通知監聽器。
當全部的 Stream 事件結束後,將會發送 Done 訊號給監聽器。
其中 Stream 分為兩種,一種為單一訂閱 (Single-subscription) stream,另一種則為廣播 (Broadcast) stream。
在Stream的生命週期裡,只允許一個監聽器監聽其變化。需要注意的是,Stream 會在有人註冊之後才開始發送事件,當監聽器取消訂閱時,將不再發送事件,縱使 Stream 的事件還沒有完全發送完畢。
另外,同一個 Stream 不允許多次註冊監聽器,就算是第一個監聽器已經被取消也是一樣。
通常用在傳送傳輸量較大的連續數據塊,例如檔案的 I/O。
允許多個監聽器註冊,當 Stream 有事件進來的時候,會立刻發送事件,縱使沒有監聽器註冊也會發。
async*
函數範例:
Stream.fromFuture(Future future)
final stream1 = Stream.fromFuture(Future.delayed(Duration(seconds:1), ()=>10));
Stream.fromFutures(Iterable<Future> futures)
List<Future<int>> generateFutures() =>
List<Future<int>>.generate(10, (index) => Future.value(index));
final stream2 = Stream.fromFutures(generateFutures());
Stream.fromIterable(Iterable element)
final stream3 = Stream.fromIterable(List<int>.generate(5, (index) => 5*index));
我們利用建構函數建立了三個 Stream,那麼要如何監聽它們呢?
listen()
直接呼叫 stream 的 listen 函數
StreamSubscription<T> listen(void onData(T event)?,
{Function? onError, void onDone()?, bool? cancelOnError});
例如:
stream.listen((event) => print(event));
將會在每一個事件到來的時候,執行 print(event)
這個動作。
除了利用 listen 函數來處理外,我們還可以使用 async
與 await for
來處理。
範例如下:
Future<int> sumStream(Stream<int> stream) async {
var sum = 0;
await for (var value in stream) {
sum += value;
}
return sum;
}
await for
可以將 Stream 使用 forEach 的方式拆解,接者回傳一個Future 的值。在 StreamController 中,利用 sink
將資料加進 (add) Stream裡:
StreamController<int> numController = StreamController();
numController.sink.add(777);
接者用 stream
將 controller 轉為 stream
numController.stream.listen((value) => print(value));
//777
利用關鍵字 async*
與 yield
也可以產生一個 Stream
Stream<int> increaseStream() async* {
for (int i = 1; i <= 10; i++) {
yield i;
}
}
本篇文章介紹了如何使用 Stream 以及建立 Stream,Stream 跟 Future 不同的是,因為 Stream 是由多個 Future 事件組成的,所以我們需要用 listener 來監聽,當事件到來時,我們才可以取得資料。
另外,在 Future 中,我們使用關鍵字 async
來處理 Future 函數,在
Stream 上需要加上星號 async*
,代表多個 Future 事件。使用 async* 要記得使用 yield
而不是 await
。