Dart | 你知道 sync*/async* 是怎麼用的嗎?

平時咱們在寫業務邏輯的時候,確定都會與網絡打交道,那確定也就避免不了異步請求,代碼相似以下:微信

int getData() async {
  Response r = await Dio().get('https://www.baidu.com');
  return r.data;
}
複製代碼

這段代碼相信不少人都很是很是熟悉了,咱們也都知道 async 是什麼意思,那加上一個星號,你還知道嗎?網絡

加上星號其實就是「函數生成器」的意思。異步

那咱們先從「sync/sync*」提及。async

sync/sync*

「sync」咱們都知道是默認程序運行的狀態,舉個例子:函數

foo1 (){
  print('foo1 start');
  for(int i = 0; i < 3; i++){
    print(i);
  }
  print('foo1 stop');
}
複製代碼

當咱們在 main函數裏運行,結果你們應該都很清楚:ui

foo1 startspa

0 1 2code

foo1 stopcdn

那所謂的函數生成器呢?接口

被「sync*」標記的函數,必定要返回一個 「Iterable」,這樣的函數生成器叫作同步生成器:

Iterable<int> foo2() sync*{
  print('foo2 start');
  for(int i = 0; i < 3; i++){
    print('運行了foo2,當前index:${i}');
    yield i;
  }
  print('foo2 stop');
}
複製代碼

這回咱們在 main 函數裏運行 foo2(),會出現什麼效果?

答案是什麼也不會發生,print也沒有打印。

這是爲何?

當咱們調用 foo2()的時候,這裏會立刻返回一個 Iterable,就像網絡請求會立刻返回一個 Feature同樣。

可是在咱們沒有調用 IterablemoveNext 的時候,當前函數體是不會執行的。

而當咱們調用了 moveNext 方法後,代碼會執行到 yield 關鍵字的位置,而且在這裏停住。

當咱們再一次調用 moveNext 後,會再恢復執行,而後再次停到 yield 關鍵字的位置,依次循環,當沒有下一個值得時候,函數會隱式的調用 return方法來終止函數。

來看一下調用方式和結果:

var b = foo2().iterator;
print('還沒開始調用 moveNext');
b.moveNext();
print('第${b.current}次moveNext');
b.moveNext();
print('第${b.current}次moveNext');
b.moveNext();
print('第${b.current}次moveNext');
複製代碼

結果爲:

還沒開始調用 moveNext
foo2 start
運行了foo2,當前index:00次moveNext
運行了foo2,當前index:11次moveNext
運行了foo2,當前index:22次moveNext
複製代碼

從運行結果上來看,咱們的說法是正確的,下面就來講一下異步生成器。

async/async*

說異步生成器以前,先來講一下普通的異步調用。

如今有一個這樣的需求,我想每隔一秒鐘請求一下數據,一共請求10次,看看有沒有人關注我等等,

若是使用原始的 async,該怎麼作?

getData() async {
  for (int i = 0; i < 10; i++){
    await Future.delayed(Duration(seconds: 1), ()async {
    	Data data = await getXXX();
      setState(){
        //業務邏輯
      };
    });
  }
}
複製代碼

這裏使用循環,而後每一秒鐘請求依次接口,返回數據後 setState();

這樣確定不行,由於你不可能一兩秒鐘就 setState()一次,

這個時候 async* 就派上用場了:

Stream<Data> getData() async* {
  for (int i = 0; i < 10; i++){
    await Future.delayed(Duration(seconds: 1));
    yield await getXXX();
  }
}
複製代碼

在頁面上,咱們能夠用 StreamBuilder 來包住,這樣每次返回數據就不用 setState() 了。

總結

其實函數生成器可能一年都用不上一兩次,可是當你用到以後,就會以爲真的很舒服。

其實我我的認爲這種函數生成器還有一種做用就是能夠讓一個函數返回多個值

另我我的建立了一個「Flutter 交流羣」,能夠添加我我的微信 「17610912320」來入羣。

推薦閱讀:

Flutter | 思路解析 WPopupMenu 仿微信聊天長按彈出菜單

Flutter | 一個關於背景顏色引起的打臉慘案

Flutter | 自定義一個 Stepper 步驟組件

img
相關文章
相關標籤/搜索