Dart 基礎(chǔ)之Future使用

什么是future

future類似android中的handler窃祝,表示稍后做的任務(wù)
使用如下:

 Future((){
      print('future do..');
      return '1';
    }).then(print);
print('main end');

可以看到main end先打印撵孤,然后打印future里面的任務(wù),最后then打印結(jié)果

main end
future do..
1

future 異常捕獲

future的異常處理有兩方法catchError和onError,

catchError(Function onError, {bool test(Object error)?})
onError<E extends Object>(
  FutureOr<T> handleError(E error, StackTrace stackTrace),
  {bool test(E error)?})

如果發(fā)生異常了疏叨,那么then方法就不會(huì)被調(diào)用掩驱,但是whenComplete方法最終也會(huì)被調(diào)用芒划,類似于Java里面的finally。
異常示例代碼如下:

 Future((){
       throw Exception('this is error');
    }).then((v){
      print(v);
    })
        .whenComplete(() => print('done'));
    print('main end')

輸出異常

main start
main end
done
Unhandled exception:
Exception: this is error

加上catchError后欧穴,

Future((){
       throw Exception('this is error');
    }).then((v){
      print(v);
    })
        .catchError((e,stackTrace){
      print('catch Error: $e');
    })
        .whenComplete(() => print('done'));
    print('main end');

輸出如下民逼,可以看到catchError捕獲到了異常,參數(shù)e為異常對(duì)象涮帘,參數(shù)stackTrace為當(dāng)前堆棧信息

main start
main end
catch Error: Exception: this is error
done

catchError方法還有個(gè)可選參數(shù) {bool test(Object error)?}拼苍,表示如果我只想捕獲某種類型的異常,
代碼如下调缨,表示我只捕獲FileSystemException類型異常

  Future((){
       throw Exception('this is error');
    }).then((v){
      print(v);
    }).catchError((e){
    print('catch Error: $e');
    },test: (e)=>e is FileSystemException)
        .whenComplete(() => print('done'));
    print('main end');

輸出異常如下疮鲫,異常沒(méi)有捕獲到

main start
main end
Unhandled exception:
Exception: this is error
done

onError是Future的擴(kuò)展方法,內(nèi)部也是調(diào)用的catchError方法

Future<T> onError<E extends Object>(
      FutureOr<T> handleError(E error, StackTrace stackTrace),
      {bool test(E error)?}) {
    // There are various ways to optimize this to avoid the double is E/as E
    // type check, but for now we are not optimizing the error path.
    return this.catchError(
        (Object error, StackTrace stackTrace) =>
            handleError(error as E, stackTrace),
        test: (Object error) => error is E && (test == null || test(error)));
  }

構(gòu)造方法microtask弦叶,sync同F(xiàn)uture({})使用相同俊犯,區(qū)別就是Future把任務(wù)放在事件隊(duì)列,microtask把任務(wù)放在微任務(wù)隊(duì)列

  Future((){
      print('future do..');
      return '1';
    }).then(print);
    Future.microtask((){
      print('microtask do');
      return '4';
    } ).then(print);
    Future.sync(() {
      print('sync do');
      return '5';}).then(print);

    print('main end');

輸出

main start
sync do
main end
2
microtask do
4
5
future do..
1

Process finished with exit code 0

等待超時(shí)timeout

timeout(Duration timeLimit, {FutureOr<T> onTimeout()?})

設(shè)置超時(shí)時(shí)間伤哺,如果任務(wù)超時(shí)了燕侠,如果onTimeout參數(shù)有設(shè)置,調(diào)用onTimeout立莉,如果onTimeout參數(shù)沒(méi)設(shè)置绢彤,直接拋出TimeoutException異常

 Future(()async{
      await Future.delayed(Duration(seconds: 2));
      return 'a';
    }).timeout(Duration(seconds: 1),onTimeout: ()=>'time out').then(print).whenComplete(() => print('done'));

輸出

time out
done

構(gòu)造方法delay:表示延遲任務(wù)

如下表示延遲1s后執(zhí)行return

 Future.delayed(Duration(seconds: 1),(){
      return '3';
    });

構(gòu)造方法error,拋出一個(gè)異常

    print('main start');
    var v = await getComplete(1,0);
    print('main end');

  Future<int> getComplete(int a,int b){
    if(b == 0){
      return Future.error(Exception('b cannot 0'));
    }
    return Future.value(a~/b);
  }

輸出如下蜓耻,可以看出程序非正常退出了茫舶,在await那行就拋出了異常。這就要求調(diào)用getComplete方法的地方一定要處理異常

main start
Unhandled exception:
Exception: b canot 0

Process finished with exit code 255

靜態(tài)方法wait媒熊,等待多個(gè)future結(jié)果

Future<List<T>> wait<T>(Iterable<Future<T>> futures,
  {bool eagerError = false, void cleanUp(T successValue)?}
 int start = DateTime.now().millisecondsSinceEpoch;
    List<dynamic> value = await Future.wait<dynamic>([
      delayedNumber(1),
      delayedString("a"),
      delayedNumber(1),
      delayedString('b'),
    ]);
    int cost = DateTime.now().millisecondsSinceEpoch-start;
    print("cost:${cost/1000} s, value:$value"); 

//模擬耗時(shí)奇适,延遲3秒
Future<int> delayedNumber(int num) async {
    await Future.delayed(const Duration(seconds: 3));
    return 2;
  }
//模擬耗時(shí)坟比,延遲2秒
  Future<String> delayedString(String value) async {
    await Future.delayed(const Duration(seconds: 2));
    return value;
  }

輸出結(jié)果如下,可以看出最終耗時(shí)并不是幾個(gè)future的總和嚷往,而是最大的耗時(shí)任務(wù)葛账,相當(dāng)于并行處理

cost:3.025 s, value:[2, a, 2, b]

靜態(tài)方法any,執(zhí)行多個(gè)future皮仁,只要有一個(gè)完成就返回結(jié)果

同樣是上述代碼籍琳,把wait換成any,返回值就不是list了贷祈,因?yàn)橹挥幸粋€(gè)結(jié)果會(huì)返回

 int start = DateTime.now().millisecondsSinceEpoch;
    dynamic value = await Future.any<dynamic>([
      delayedNumber(1),
      delayedString("a"),
      delayedNumber(1),
      delayedString('b'),
    ]);
    int cost = DateTime.now().millisecondsSinceEpoch-start;
    print("cost:${cost/1000} s, value:$value"); 

輸出結(jié)果趋急,返回的用時(shí)最小的a

cost:2.019 s, value:a

靜態(tài)方法forEach,對(duì)集合每個(gè)元素執(zhí)行action操作

forEach<T>(Iterable<T> elements, FutureOr action(T element))

同時(shí)這個(gè)方法的調(diào)用then是拿不到數(shù)據(jù)的
示例代碼如下

 print('main start');
Future.forEach([1,2,3,4], (element) {
      print(element);
      return 'a';
    }).then((value) => print(value));
    print('main end');

輸出势誊,可以看出呜达,和正常的集合遍歷沒(méi)啥區(qū)別,而且是立馬執(zhí)行的

main start
1
2
3
4
main end
null

修改代碼action返回值為future粟耻,其他不變查近,

Future.forEach([1,2,3,4], (element) {
      print(element);
      return Future.value('a');
    }).then((value) => print(value));

輸出如下,可以看到除了第一個(gè)元素挤忙,后面的元素在稍后執(zhí)行

main start
1
main end
2
3
4
null

靜態(tài)方法doWhile:返回為true時(shí)會(huì)一直重復(fù)霜威,直到返回false

適合用在有輪詢情況的業(yè)務(wù),沒(méi)有達(dá)到條件就一直輪詢
示例如下册烈,當(dāng)value為3時(shí)才執(zhí)行then語(yǔ)句

 Future task = Future.doWhile(()async{
      await Future.delayed(const Duration(seconds: 1));
      value++;
      if (value == 3) {
        return false;
      }
      return true;
    });
task.then((_){
      print('Finished with $value');
    });

輸出

Finished with 3

Completer

如果我們寫(xiě)的一個(gè)方法A返回的是Future類型戈泼,,但是我們A方法里面調(diào)用了B方法赏僧,B方法是個(gè)異步方法大猛,但是B方法返回是利用回調(diào)返回,
這種場(chǎng)景比較常見(jiàn)我們調(diào)用其他人的異步方法時(shí)次哈,如果這個(gè)異步方法返回的是Future胎署,那我們可以直接用await獲取異步結(jié)果吆录,但是如果不是窑滞,這個(gè)時(shí)候如果我們還想用Future返回,就可以用Completer了

例子如下,call方法通過(guò)callback回調(diào)結(jié)果恢筝,

 Future<int> testCompleter(){
    Completer<int> c = Completer();
   call((d){
      c.complete(d);
    });
    return c.future;
  }
  void call(Function callback){
    Future.delayed(Duration(seconds: 1),(){
       callback(123);
    });
  }

    print('main start');
    testCompleter().then(print);
    print('main end');

輸出

main start
main end
123

Process finished with exit code 0
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哀卫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子撬槽,更是在濱河造成了極大的恐慌此改,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侄柔,死亡現(xiàn)場(chǎng)離奇詭異共啃,居然都是意外死亡占调,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)移剪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)究珊,“玉大人,你說(shuō)我怎么就攤上這事纵苛〗虽蹋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵攻人,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)循帐,這世上最難降的妖魔是什么给赞? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮蓬坡,結(jié)果婚禮上瑟蜈,老公的妹妹穿的比我還像新娘。我一直安慰自己渣窜,他們只是感情好铺根,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著乔宿,像睡著了一般位迂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上详瑞,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天掂林,我揣著相機(jī)與錄音,去河邊找鬼坝橡。 笑死泻帮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的计寇。 我是一名探鬼主播锣杂,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼番宁!你這毒婦竟也來(lái)了元莫?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蝶押,失蹤者是張志新(化名)和其女友劉穎踱蠢,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體棋电,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡茎截,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年苇侵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片企锌。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡衅檀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出霎俩,到底是詐尸還是另有隱情哀军,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布打却,位于F島的核電站杉适,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏柳击。R本人自食惡果不足惜猿推,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捌肴。 院中可真熱鬧蹬叭,春花似錦、人聲如沸状知。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)饥悴。三九已至坦喘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間西设,已是汗流浹背瓣铣。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贷揽,地道東北人棠笑。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像禽绪,于是被迫代替她去往敵國(guó)和親蓖救。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容