【-Flutter/Dart 語法補遺-】 sync* 和 async* 、yield 和yield* 、async 和 await

前言

類別 關鍵字 返回類型 搭檔
多元素同步 sync* Iterable<T> yield、yield*
單元素異步 async Future<T> await
多元素異步 async* Stream<T> yield、yield* 、await

下面就用幾個emoji,認識一下這幾個關鍵字吧git


1、多元素同步函數生成器

1. sync*yield

sync*是一個dart語法關鍵字它標註在函數{ 以前,其方法必須返回一個 Iterable<T>對象github

👿 的碼爲\u{1f47f}。下面是使用sync*生成後10個emoji迭代(Iterable)對象的方法編程

main() {
  getEmoji(10).forEach(print);
}

Iterable<String> getEmoji(int count) sync* {
  Runes first = Runes('\u{1f47f}');
  for (int i = 0; i < count; i++) {
    yield String.fromCharCodes(first.map((e) => e + i));
  }
}
複製代碼
👿
💀
💁
💂
💃
💄
💅
💆
💇
💈
複製代碼

二、sync*yield*

yield*又是何許人也? 記住一點yield*後面的表達式是一個Iterable<T>對象微信

好比下面getEmoji方法是核心,如今想要打印每次的時間,使用getEmojiWithTime yield*以後的getEmoji(count).map((e)...即是一個可迭代對象Iterable<String>markdown

main() {
  getEmojiWithTime(10).forEach(print);
}

Iterable<String> getEmojiWithTime(int count) sync* {
  yield* getEmoji(count).map((e) => '$e -- ${DateTime.now().toIso8601String()}');
}

Iterable<String> getEmoji(int count) sync* {
  Runes first = Runes('\u{1f47f}');
  for (int i = 0; i < count; i++) {
    yield String.fromCharCodes(first.map((e) => e + i));
  }
}
複製代碼
👿 -- 2020-05-20T07:01:07.163407
💀 -- 2020-05-20T07:01:07.169451
💁 -- 2020-05-20T07:01:07.169612
💂 -- 2020-05-20T07:01:07.169676
💃 -- 2020-05-20T07:01:07.169712
💄 -- 2020-05-20T07:01:07.169737
💅 -- 2020-05-20T07:01:07.169760
💆 -- 2020-05-20T07:01:07.169789
💇 -- 2020-05-20T07:01:07.169812
💈 -- 2020-05-20T07:01:07.169832
複製代碼

2、異步處理: asyncawait

async是一個dart語法關鍵字它標註在函數{ 以前,其方法必須返回一個 Future<T>對象app

對於耗時操做,一般用Future<T>對象異步處理,下面fetchEmoji方法模擬2s加載耗時less

main() {
  print('程序開啓--${DateTime.now().toIso8601String()}');
  fetchEmoji(1).then(print);
}

Future<String> fetchEmoji(int count) async{
  Runes first = Runes('\u{1f47f}');
  await Future.delayed(Duration(seconds: 2));//模擬耗時
  print('加載結束--${DateTime.now().toIso8601String()}');
  return String.fromCharCodes(first.map((e) => e + count));
}
複製代碼
加載開始--2020-05-20T07:20:32.156074
加載結束--2020-05-20T07:20:34.175806
💀
複製代碼

3、多元素異步函數生成器:

1.async*yieldawait

async*是一個dart語法關鍵字它標註在函數{ 以前,其方法必須返回一個 Stream<T>對象異步

下面fetchEmojisasync*標註,因此返回的必然是Stream對象
注意被async*標註的函數,能夠在其內部使用yield、yield*、await關鍵字async

main() {
  fetchEmojis(10).listen(print);
}

Stream<String> fetchEmojis(int count) async*{
  for (int i = 0; i < count; i++) {
    yield await fetchEmoji(i);
  }
}

Future<String> fetchEmoji(int count) async{
  Runes first = Runes('\u{1f47f}');
  print('加載開始--${DateTime.now().toIso8601String()}');
  await Future.delayed(Duration(seconds: 2));//模擬耗時
  print('加載結束--${DateTime.now().toIso8601String()}');
  return String.fromCharCodes(first.map((e) => e + count));
}
複製代碼
加載開始--2020-05-20T07:28:28.394205
加載結束--2020-05-20T07:28:30.409498
👿
加載開始--2020-05-20T07:28:30.416714
加載結束--2020-05-20T07:28:32.419157
💀
加載開始--2020-05-20T07:28:32.419388
加載結束--2020-05-20T07:28:34.423053
💁
加載開始--2020-05-20T07:28:34.423284
加載結束--2020-05-20T07:28:36.428161
💂
加載開始--2020-05-20T07:28:36.428393
加載結束--2020-05-20T07:28:38.433409
💃
加載開始--2020-05-20T07:28:38.433647
加載結束--2020-05-20T07:28:40.436491
💄
加載開始--2020-05-20T07:28:40.436734
加載結束--2020-05-20T07:28:42.440696
💅
加載開始--2020-05-20T07:28:42.441255
加載結束--2020-05-20T07:28:44.445558
💆
加載開始--2020-05-20T07:28:44.445801
加載結束--2020-05-20T07:28:46.448190
💇
加載開始--2020-05-20T07:28:46.448432
加載結束--2020-05-20T07:28:48.452624
💈
複製代碼

2.async*yield*await

和上面的yield*同理,async*方法內使用yield*,其後對象必須是Stream<T>對象ide

以下getEmojiWithTimefetchEmojis流進行map轉換,前面須要加yield*

main() {
  getEmojiWithTime(10).listen(print);
}

Stream<String> getEmojiWithTime(int count) async* {
  yield* fetchEmojis(count).map((e) => '$e -- ${DateTime.now().toIso8601String()}');
}

Stream<String> fetchEmojis(int count) async*{
  for (int i = 0; i < count; i++) {
    yield await fetchEmoji(i);
  }
}

Future<String> fetchEmoji(int count) async{
  Runes first = Runes('\u{1f47f}');
  await Future.delayed(Duration(seconds: 2));//模擬耗時
  return String.fromCharCodes(first.map((e) => e + count));
}
複製代碼
👿 -- 2020-05-20T07:35:09.461624
💀 -- 2020-05-20T07:35:11.471223
💁 -- 2020-05-20T07:35:13.476712
💂 -- 2020-05-20T07:35:15.482848
💃 -- 2020-05-20T07:35:17.489429
💄 -- 2020-05-20T07:35:19.491214
💅 -- 2020-05-20T07:35:21.497086
💆 -- 2020-05-20T07:35:23.500867
💇 -- 2020-05-20T07:35:25.505379
💈 -- 2020-05-20T07:35:27.511723
複製代碼

4、Stream的使用-StreamBuilder

Stream在組件層面最經常使用的就數StreamBuilder,本文只是簡單用一下,之後會有專文
StreamBuilder組件使用的核心就是,它接受一個Stream對象,

根據builder函數在流元素的不一樣狀態下構建不一樣的界面。


1.頂部組件
import 'dart:async';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: Scaffold(
          appBar: AppBar(),
          body: HomePage(),
        ));
  }
}
複製代碼

2.StreamBuilder組件的使用
class HomePage extends StatefulWidget {
  
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
   Stream<String> _stream;
  @override
  void initState() {
    super.initState();
    _stream= fetchEmojis(10);
  }
  
  @override
  Widget build(BuildContext context) {
    return Center(
      child: StreamBuilder<String>(
        builder: _buildChildByStream,
        stream: _stream,
      ),
    );
  }

  Widget _buildChildByStream(
      BuildContext context, AsyncSnapshot<String> snapshot) {
    switch(snapshot.connectionState){
      case ConnectionState.none:
        break;
      case ConnectionState.waiting:
        return CircularProgressIndicator();
        break;
      case ConnectionState.active:
        return Text(snapshot.requireData,style: TextStyle(fontSize: 60));
        break;
      case ConnectionState.done:
        return Text('Stream Over--${snapshot.requireData}',style: TextStyle(fontSize: 30),);
        break;
    }
    return Container();
  }

   Stream<String> fetchEmojis(int count) async* {
     for (int i = 0; i < count; i++) {
       yield await fetchEmoji(i);
     }
   }

   Future<String> fetchEmoji(int count) async {
     Runes first = Runes('\u{1f47f}');
     await Future.delayed(Duration(seconds: 1)); //模擬耗時
     return String.fromCharCodes(first.map((e) => e + count));
   }
}
複製代碼

題外話:

若是你使用過flutter_bloc,會用到async*,如今再來看,是否是更清楚了一點。

class CounterBloc extends Bloc<CounterEvent, int> {
  @override
  int get initialState => 0;

  @override
  Stream<int> mapEventToState(CounterEvent event) async* {
    switch (event) {
      case CounterEvent.decrement:
        yield state - 1;
        break;
      case CounterEvent.increment:
        yield state + 1;
        break;
    }
  }
}
複製代碼

尾聲

歡迎Star和關注FlutterUnit 的發展,讓咱們一塊兒攜手,成爲Unit一員。

另外本人有一個Flutter微信交流羣,歡迎小夥伴加入,共同分享Flutter的知識,期待與你的交流與切磋。

@張風捷特烈 2020.05.20 未允禁轉

個人公衆號:編程之王
聯繫我--郵箱:1981462002@qq.com --微信:zdl1994328
~ END ~

本文同步分享在 博客「張風捷特烈」(JueJin)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索