Dart異步編程學習札記

Dart異步編程學習札記

Dart是一門單線程,所以在開發(fā)中我們不需要像其他多線程語言一樣需要考慮資源競爭問題句葵,也沒有鎖的概念,而Dart編程中如果需要實現(xiàn)等待一個任務完成的同時進行別的任務的操作時卦羡,就需要使用異步操作來實現(xiàn)了功氨。

而要在Dart中執(zhí)行異步操作,則需要使用Future類刊懈。

Future的使用

最簡單的这弧,我們可以直接這樣寫:

void main() {
  print("任務 1");
  Future((){
    print("任務 2");
  });
  print("任務 3");
}

此時控制臺打印:

flutter: 任務 1
flutter: 任務 3
flutter: 任務 2

可以看到俏讹,雖然任務 2在任務 3之前添加当宴,但是卻在任務3執(zhí)行完畢后才執(zhí)行。

而且與多線程不同泽疆,異步任務不是與同步任務同時進行户矢,而是要等待主線程空閑的時候,才會去執(zhí)行異步任務殉疼。

void main() {
  print("任務 1");
  Future(() {
    print("任務 2");
  });
  sleep(Duration(seconds: 5));
  print("任務 3");
}

執(zhí)行后:

flutter: 任務 1
flutter: 任務 3
flutter: 任務 2

吐槽一下Dart梯浪,單線程語言的性能真心不如多線程語言。瓢娜。挂洛。

如果我們需要在異步操作中修改一個變量的值,并且在后續(xù)的同步操作中獲取到該值眠砾,如:

void main() {
  print("任務 1");
  Future(() {
    _data = "2";
    print("任務 2");
  });
  print("任務 3");
  print("data value is: ${_data}");
}
String _data = "0";

顯然這樣寫是無法得到我們想要的結果的虏劲,打印結果如下:

flutter: 任務 1
flutter: 任務 3
flutter: data value is: 0
flutter: 任務 2

要解決這個問題,可以使用await和async關鍵字。

await和async

首先我們將異步操作放到一個函數(shù)中, 并且這個函數(shù)顯然是一個異步函數(shù)柒巫,因此我們要在函數(shù)名后面添加一個async關鍵字励堡,表示這是一個異步函數(shù)

僅僅一個async關鍵字是無法滿足我們需求的,我們還需要在異步操作前添加一個await關鍵字堡掏,需要注意的是,await要在異步函數(shù)中才能使用应结。

void asyncTask() async {
   await Future((){
    _data = "2";
    print("任務 2");
   });
   print("data value is: ${_data}");
}

打印結果為

flutter: 任務 2
flutter: data value is: 2

繼續(xù)對await關鍵字探究,如果我們在asyncTask函數(shù)中添加任務4泉唁,是否會先執(zhí)行任務4呢鹅龄?

void asyncTask() async {
   await Future((){
    _data = "2";
    print("任務 2");
   });
   print("data value is: ${_data}");
   print("任務 4");
}

flutter: 任務 2
flutter: data value is: 2

顯然任務4最后才執(zhí)行,而寫在main函數(shù)中的任務3先執(zhí)行了亭畜,由此我們可以判斷扮休,await關鍵字作用域為所在異步函數(shù)內,聲明await后贱案,異步函數(shù)后續(xù)操作都必須等待await修飾的異步操作執(zhí)行完畢后才能執(zhí)行肛炮。

處理Future結果

查看源文件,我們發(fā)現(xiàn)Future((){})其實是一個工廠構造函數(shù)宝踪,我們拿到future對象侨糟,進行一些操作

Future.then()

這是一個用來注冊Future完成是要調用的回調,它會在future完成后立馬執(zhí)行瘩燥,而在then的回調中有兩個參數(shù)秕重,分別是:
Future<R> then<R>(FutureOr<R> onValue(T value), {Function onError});
顯而易見,onValue是任務成功的回調厉膀,而onError則是事件錯誤的回調溶耘。

另外,onValue回調中帶有一個參數(shù)服鹅,我們可以通過下面的代碼看到它的用法:

 Future((){
    print("任務 2");
    return "value success";
   }).then((value) {
     print("then 任務");
     print(value);
   });

執(zhí)行結果:

flutter: 任務 2
flutter: then 任務
flutter: value success

顯然凳兵,onValue中的value參數(shù),實際上就是Future中return的值企软。這個我們就可以實現(xiàn)不用await等待庐扫,通過then拿到異步操作返回的結果。這種寫法仗哨,顯然比await清晰許多形庭。

繼續(xù)探究onError:

Future(() {
    print("任務 2");
    throw Exception("future error");
  }).then((value) {
    print("then 任務");
    print(value);
  }, onError: (error) {
    print(error);
  });

執(zhí)行后結果:

flutter: 任務 2
flutter: Exception: future error

可以到,如果future中拋出了一個錯誤厌漂,那么我們可以onError回調中處理這個錯誤萨醒,并且onVaule回調將不會執(zhí)行。

Future.catchError()

很明顯苇倡,這個回調也是用來處理error的:

Future(() {
    print("任務 2");
    throw Exception("future error");
  }).catchError((error) {
    print(error);
  });

結果:

flutter: 任務 2
flutter: Exception: future error

另外富纸,如果我們這么寫:

  final future = Future(() {
    throw Exception("error");
  });

  future.catchError((error) {
    print("catchError $error");
  });

  future.then((value) {
    print("then 任務");
  }, onError: (e) {
    print("onError $e");
  });

結果會出現(xiàn):

flutter: catchError Exception: error
flutter: onError Exception: error

從上面的結果可以看出囤踩,onError和catchError是可以同樣捕獲錯誤的

我們接著探究:

  final future = Future(() {
    throw Exception("error");
  });

  future.catchError((error) {
    print("catchError $error");
  }).then((value) {
    print("then 任務");
  }, onError: (e) {
    print("onError $e");
  });

結果為:

flutter: catchError Exception: error
flutter: then 任務

而如果我們這么寫

  final future = Future(() {
    throw Exception("error");
  });

  future.then((value) {
    print("then 任務");
  }, onError: (e) {
    print("onError $e");
  }).catchError((error) {
    print("catchError $error");
  });

結果為

flutter: onError Exception: error

因此,我們可以得出結論:future采用鏈式編程的時候晓褪,如果當前future拋出異常高职,錯誤信息會由下一個future的onError或catchError接受處理,并且不會繼續(xù)往下一個future傳遞辞州。

Future.whenComplete()

和then相似的是,whenComplete也是在Future執(zhí)行完畢后調用寥粹,但不同的是变过,不管future中是否拋出異常,whenComplete都會執(zhí)行

  Future(() {
    print("任務 2");
    throw Exception("future error");
  }).whenComplete(() {
    print("whenComplete");
  }).catchError((error) {
    print(error);
  });

flutter: 任務 2
flutter: whenComplete
flutter: Exception: future error

多個Future的情況

執(zhí)行以下代碼:

  Future(() {
    print("future 1");
  }).then((value) => print("then 1"));

  Future(() {
    print("future 2");
  }).then((value) => print("then 2"));

  Future(() {
    print("future 3");
  }).then((value) => print("then 3"));

執(zhí)行結果:

flutter: future 1
flutter: then 1
flutter: future 2
flutter: then 2
flutter: future 3
flutter: then 3

可以看到涝涤,多個Future的情況媚狰,執(zhí)行順序是按照添加的順序執(zhí)行的,如果Future后有then回調阔拳,那么執(zhí)行當前future執(zhí)行完后會立馬執(zhí)行then回調崭孤,而不是執(zhí)行下一個Future。

顯然糊肠,所有Future都是被添加到某種隊列中辨宠,按照先進先出的方式進行執(zhí)行。查看官方文檔可以知道货裹,確實在Dart中有事件隊列(event queue)嗤形、微任務隊列(microtask queue)兩種隊列,而Future異步任務弧圆,是被添加到事件隊列中赋兵。

Dart的事件循環(huán)(event loop)

Dart中,有兩種隊列:
1. 事件隊列(event queue)搔预,包含所有的外來事件:I/O霹期、mouse events、drawing events拯田、timers历造、isolate之間的信息傳遞。
2. 微任務隊列(microtask queue)勿锅,表示一個短時間內就會完成的異步任務帕膜。它的優(yōu)先級最高,高于event queue溢十,只要隊列中還有任務垮刹,就可以一直霸占著事件循環(huán)。microtask queue添加的任務主要是由 Dart內部產(chǎn)生张弛。

在每一次事件循環(huán)中荒典,Dart總是先去第一個微任務隊列中查詢是否有可執(zhí)行的任務酪劫,如果沒有,才會處理后續(xù)的事件隊列

事件循環(huán).jpg

實踐一下:

void main() {
  print("任務 1");
  Future((){
    print("任務 2");
  });
  scheduleMicrotask((){
    print("任務 4");
  });
  print("任務 3");
}

執(zhí)行結果為

flutter: 任務 1
flutter: 任務 3
flutter: 任務 4
flutter: 任務 2

可以看到寺董,盡管任務2先被添加到事件隊列覆糟,但是最終的執(zhí)行結果是微任務隊列中的任務4先被執(zhí)行。

通過以上的解釋遮咖,我們就可以分析下面代碼的打印順序

  Future x1 = Future(() => null);
  x1.then((value) {
    print('6');
    scheduleMicrotask(() => print('7'));
  }).then((value) => print('8'));
  Future x = Future(() => print('1'));
  x.then((value) {
    print('4');
    Future(() => print('9'));
  }).then((value) => print('10'));

  Future(() => print('2'));
  scheduleMicrotask(() => print('3'));

  print('5');

  1. 首先滩字,同步任務 5 肯定是先被執(zhí)行,
  2. 因為 7 是在x1的then中才會被添加御吞,所以先執(zhí)行的是外部已經(jīng)添加到微任務隊列中的3
  3. 3執(zhí)行完后微任務隊列為空麦箍,走到事件對列,此時事件隊列中為x1,1,2,所以會先執(zhí)行x1的任務陶珠,而x1中任務為空挟裂,會走到then中6,所以下一個打印的是6揍诽,
  4. 而 6 執(zhí)行完后還有一個then诀蓉,所以也會立即執(zhí)行then中的8,
  5. 此時暑脆,7已經(jīng)被添加到微任務隊列中渠啤,所以下一個執(zhí)行的是7,
  6. 微任務隊列又空了饵筑,繼續(xù)執(zhí)行事件隊列下一個任務1埃篓,
  7. 而后執(zhí)行then中的4,下一步操作中根资,
  8. 9也被添加到事件隊列中架专,所以此時事件隊列中還有2和9,
  9. 4打印完后立即執(zhí)行then中的10玄帕,
  10. 隨后再將事件隊列中剩余的任務2和9執(zhí)行完畢部脚,所以最終的打印順序為:

5,3裤纹,6委刘,8,7鹰椒,1锡移,4,10漆际,2淆珊,9

執(zhí)行看看:

flutter: 5
flutter: 3
flutter: 6
flutter: 8
flutter: 7
flutter: 1
flutter: 4
flutter: 10
flutter: 2
flutter: 9

與分析一致。

總結

盡管Dart是一門單線程線程語言奸汇,但我們仍然可以使用異步操作去執(zhí)行實現(xiàn)一些諸如網(wǎng)絡獲取數(shù)據(jù)施符,寫入數(shù)據(jù)庫等耗時操作往声,避免阻礙正常事件的執(zhí)行。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末戳吝,一起剝皮案震驚了整個濱河市浩销,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌听哭,老刑警劉巖慢洋,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異陆盘,居然都是意外死亡且警,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門礁遣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人肩刃,你說我怎么就攤上這事祟霍。” “怎么了盈包?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵沸呐,是天一觀的道長。 經(jīng)常有香客問我呢燥,道長崭添,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任叛氨,我火速辦了婚禮呼渣,結果婚禮上,老公的妹妹穿的比我還像新娘寞埠。我一直安慰自己屁置,他們只是感情好,可當我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布仁连。 她就那樣靜靜地躺著蓝角,像睡著了一般。 火紅的嫁衣襯著肌膚如雪饭冬。 梳的紋絲不亂的頭發(fā)上使鹅,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天,我揣著相機與錄音昌抠,去河邊找鬼患朱。 笑死,一個胖子當著我的面吹牛扰魂,可吹牛的內容都是我干的麦乞。 我是一名探鬼主播蕴茴,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼姐直!你這毒婦竟也來了倦淀?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤声畏,失蹤者是張志新(化名)和其女友劉穎撞叽,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體插龄,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡愿棋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了均牢。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糠雨。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖徘跪,靈堂內的尸體忽然破棺而出甘邀,到底是詐尸還是另有隱情,我是刑警寧澤垮庐,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布松邪,位于F島的核電站,受9級特大地震影響哨查,放射性物質發(fā)生泄漏逗抑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一寒亥、第九天 我趴在偏房一處隱蔽的房頂上張望邮府。 院中可真熱鬧,春花似錦溉奕、人聲如沸挟纱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽紊服。三九已至,卻和暖如春胸竞,著一層夾襖步出監(jiān)牢的瞬間欺嗤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工卫枝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留煎饼,地道東北人。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓校赤,卻偏偏與公主長得像吆玖,于是被迫代替她去往敵國和親筒溃。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,562評論 2 349