Flutter Bloc 03 - 基礎物件 同步、非同步 await yield 操作

會煮咖啡的貓發表於2021-03-23

本節目標

  • 同步、非同步 sync async
  • 關鍵字 await yield
  • 加上 * 的區別

視訊

www.bilibili.com/video/BV1JZ…

程式碼

github.com/ducafecat/f…

正文

在 BLOC 中常見 yield yield* Stream

計算器 Bloc 程式碼

我們可以發現在 bloc 模組中,非常多 yield* yield async* ,如何正確使用還是很重要的,所以這篇文章把同步、非同步的對應的操作符都整理出來。

class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(CounterInitial(0));

  int counterNum = 0;

  @override
  Stream<CounterState> mapEventToState(
    CounterEvent event,
  ) async* {
    if (event is CounterIncrementEvent) {
      yield* _mapIncrementEventToState(event);
    } else if (event is CounterSubductionEvent) {
      yield* _mapSubductionEventToState(event);
    }
  }

  Stream<CounterState> _mapIncrementEventToState(
      CounterIncrementEvent event) async* {
    this.counterNum += 1;
    yield CounterChange(this.counterNum);
  }

  Stream<CounterState> _mapSubductionEventToState(
      CounterSubductionEvent event) async* {
    this.counterNum -= 1;
    yield CounterChange(this.counterNum);
  }
}

複製程式碼

同步 sync* + yield

同步 sync 後返回 Iterable 可序列化物件

  • 程式碼
main() {
  getList(10).forEach(print);
}

Iterable<int> getList(int count) sync* {
  for (int i = 0; i < count; i++) {
    yield i;
  }
}
複製程式碼
  • 輸出
0
1
2
3
4
5
6
7
8
9
Exited
複製程式碼
  • 我如果把 sync* 去掉,編輯器會提示這是固定格式。

同步 sync* + yield*

帶上 * 因為 yield 返回物件是 Iterable

  • 程式碼
main() {
  getList(10).forEach(print);
}

Iterable<int> getList(int count) sync* {
  yield* generate(count);
}

Iterable<int> generate(int count) sync* {
  for (int i = 0; i < count; i++) {
    yield i;
  }
}
複製程式碼
  • 輸出
0
1
2
3
4
5
6
7
8
9
Exited

複製程式碼
  • 我把 yield* 去掉後,提示返回 Iterable<T> 必須帶上 *

非同步 async + await

Future + async + await 經典配合

常見場景,等待非同步完成,比如拉取資料、 IO 操作

  • 程式碼
main() {
  print("start..........");
  getList(10).then(print);
}

Future<int> getList(int count) async {
  await sleep();
  for (int i = 0; i < count; i++) {
    return i;
  }
  return 99;
}

Future sleep() async {
  return Future.delayed(Duration(seconds: 3));
}
複製程式碼
  • 輸出
start..........
0
Exited
複製程式碼

這裡就直接返回了, 沒有後續的任何操作。

非同步 async* + yield

帶上 * 後,yield 返回 Stream 物件

接收方用 listen(...)

  • 程式碼
main() {
  getList(10).listen(print);
}

Stream<int> getList(int count) async* {
  for (int i = 0; i < count; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i;
  }
}
複製程式碼
  • 輸出
0
1
2
3
4
5
6
7
8
9
Exited
複製程式碼
  • yield 必須和 async*sync* 配套使用

非同步 async* + yield*

yield* 後返回的是另一個 Stream 物件

  • 程式碼
main() {
  getList(10).listen(print);
}

Stream<int> getList(int count) async* {
  yield* generate(count);
}

Stream<int> generate(int count) async* {
  for (int i = 0; i < count; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i;
  }
}

複製程式碼
  • 輸出
0
1
2
3
4
5
6
7
8
9
Exited
複製程式碼
  • 返回 Stream<T> 型別必須是用 yield* 的方式


© 貓哥

ducafecat.tech

ducafecat.gitee.io

相關文章