1. 程式人生 > 實用技巧 >Dart語言之 非同步支援

Dart語言之 非同步支援

Dart類庫有非常多的返回Future或者Stream物件的函式。 這些函式被稱為非同步函式:它們只會在設定好一些耗時操作之後返回,比如像 IO操作。而不是等到這個操作完成。

asyncawait關鍵詞支援了非同步程式設計,允許您寫出和同步程式碼很像的非同步程式碼。

Future與JavaScript中的Promise非常相似,表示一個非同步操作的最終完成(或失敗)及其結果值的表示。簡單來說,它就是用於處理非同步操作的,非同步處理成功了就執行成功的操作,非同步處理失敗了就捕獲錯誤或者停止後續操作。一個Future只會對應一個結果,要麼成功,要麼失敗。

Future 的所有API的返回值仍然是一個Future物件,所以可以很方便的進行鏈式呼叫。
Future.delayed(new Duration(seconds: 2),(){
   //return "hi world!";
   throw AssertionError("Error");
}).then((data){
   //執行成功會走到這裡 
   print(data);
}).catchError((e){
   //執行失敗會走到這裡   
   print(e);
}).whenComplete((){
   //無論成功或失敗都會走到這裡
});
//可以看出和JavaScript的Promise使用一毛一樣
Future.wait
有些時候,我們需要等待多個非同步任務都執行結束後才進行一些操作,比如我們有一個介面,需要先分別從兩個網路介面獲取資料,獲取成功後,我們需要將兩個介面資料進行特定的處理後再顯示到UI介面上,應該怎麼做?答案是Future.wait,它接受一個Future陣列引數,只有陣列中所有Future都執行成功後,才會觸發then的成功回撥,只要有一個Future執行失敗,就會觸發錯誤回撥。下面,我們通過模擬Future.delayed 來模擬兩個資料獲取的非同步任務,等兩個非同步任務都執行成功時,將兩個非同步任務的結果拼接打印出來,程式碼如下:

Future.wait([
  
// 2秒後返回結果 Future.delayed(new Duration(seconds: 2), () { return "hello"; }), // 4秒後返回結果 Future.delayed(new Duration(seconds: 4), () { return " world"; }) ]).then((results){ print(results[0]+results[1]); }).catchError((e){ print(e); });
執行上面程式碼,4秒後你會在控制檯中看到“hello world”。

async await語法糖

task() async {
   try{
    String id = await login("alice","******");
    String userInfo = await getUserInfo(id);
    await saveUserInfo(userInfo);
    //執行接下來的操作   
   } catch(e){
    //錯誤處理   
    print(e);   
   }  
}
async用來表示函式是非同步的,定義的函式會返回一個Future物件,可以使用then方法添加回調函式。
await 後面是一個Future,表示等待該非同步任務完成,非同步完成後才會往下走;await必須出現在 async 函式內部。
可以看到,我們通過async/await將一個非同步流用同步的程式碼表示出來了。

其實,無論是在JavaScript還是Dart中,async/await都只是一個語法糖,編譯器或直譯器最終都會將其轉化為一個Promise(Future)的呼叫鏈。

上述程式碼 等價於

login("alice","******").then((id){
      return getUserInfo(id);
}).then((userInfo){
    return saveUserInfo(userInfo);
}).then((e){
   //執行接下來的操作 
}).catchError((e){
  //錯誤處理  
  print(e);
});

Stream //TODO 暫時沒有遇到具體場景, 以後補充

Stream 也是用於接收非同步事件資料,和Future 不同的是,它可以接收多個非同步操作的結果(成功或失敗)。 也就是說,在執行非同步任務時,可以通過多次觸發成功或失敗事件來傳遞結果資料或錯誤異常。 Stream 常用於會多次讀取資料的非同步任務場景,如網路內容下載、檔案讀寫等。舉個例子:

Stream.fromFutures([
  // 1秒後返回結果
  Future.delayed(new Duration(seconds: 1), () {
    return "hello 1";
  }),
  // 丟擲一個異常
  Future.delayed(new Duration(seconds: 2),(){
    throw AssertionError("Error");
  }),
  // 3秒後返回結果
  Future.delayed(new Duration(seconds: 3), () {
    return "hello 3";
  })
]).listen((data){
   print(data);
}, onError: (e){
   print(e.message);
},onDone: (){

});
上面的程式碼依次會輸出:

I/flutter (17666): hello 1
I/flutter (17666): Error
I/flutter (17666): hello 3