小菜前幾天剛學習了 Future 實作異步操作的部分方法,主要包括構造方法和常用的靜态方法;小菜今天繼續學習 Future 其他知識和 async-await 方式實作異步操作;
Future 嵌套
小菜在上篇部落格中未做 Future 嵌套嘗試,有很多場景需要多個異步處理,且每個異步都需要上個異步傳回的結果 then() 之後才可以繼續,此時可以用 Future 嵌套方式;但如果潛套方法較多可能會對今後的代碼維護造成一定影響,即常說到的 Callback hell;
_futureMoreThen() {
Future.delayed(Duration(seconds: 3), () {
return 'Future.delayed 3s!';
}).then((val) {
print('Future -> then(1) -> $val');
return 'then 1';
}).then((val) {
print('Future -> then(2) -> $val');
return 'then 2';
}).then((val) {
print('Future -> then(3) -> $val');
return 'then 3';
}).whenComplete(() => print('Future whenComplete!'));
}

_futureMoreThen02() {
Future.delayed(Duration(seconds: 3), () {
return 'Future.delayed 3s!';
}).then((val) {
print('Future -> then(1) -> $val');
return Future.delayed(Duration(seconds: 2), () {
return 'Future.delayed 2s!';
}).then((val) {
print('Future -> then(2) -> $val');
return Future.delayed(Duration(seconds: 2), () {
return 'Future.delayed 2s!';
}).then((val) {
print('Future -> then(3) -> $val');
});
});
}).whenComplete(() => print('Future whenComplete!'));
}
async-await
Future 也可以通過 async-await 實作異步操作;其使用場景通常是在多個 Future 串聯起來,多層級嵌套而導緻的 Callback hell,使用 async-await 實作異步;
async
async 用來修飾的異步方法最終将傳回值封裝成 Future 對象;
await
await 會把自動把該方法進入阻塞狀态,一直待任務執行完成并傳回對應值;
案例嘗試
小菜先嘗試了基本的 async-await 用法;
(a.) 小菜未采用 async 和 await 關鍵詞,此時 Future.delayed() 傳回的是一個 Future 對象,不能同步的擷取傳回資料;
print(_function01());
_function01() {
var result = Future.delayed(Duration(seconds: 3), () {
return 'Future.delayed 3s!';
}).then((val) => print('Function01 -> then() -> $val'))
.whenComplete(() => print('Function01 -> whenComplete!'));
return 'Function01 -> $result';
}
(b.) 小菜僅添加了 async 關鍵詞,将該方法修飾為異步方法,依舊不能直接擷取傳回資料
print(_function01());
Future<String> _function02() async {
var result = Future.delayed(Duration(seconds: 3), () {
return 'Future.delayed 3s!';
}).then((val) => print('Function02 -> then() -> $val'))
.whenComplete(() => print('Function02 -> whenComplete!'));
return 'Function02 -> $result';
}
(c.) 小菜添加了 async 和 await 兩個關鍵詞,編譯器最終會将其轉化為一個 Promise(Future) 的調用鍊,可以待異步完成之後擷取傳回結果;此時 Future 不能設定 then() 回調方法等;
print(await _function03());
_function03() async {
var result = await Future.delayed(Duration(seconds: 3), () {
return 'Future.delayed 3s!';
});
return 'Function03 -> $result';
}
(d.) 小菜嘗試隻用 await,此時提示 The await expression can only used in an async function,await 隻能用在 async 方法内部;
(e.) 采用 async-await 方式時,對于異常的捕獲,可以通過 Future.catchError() 來處理,還可以采用最常用的 try-catch-finally 方式,小菜簡單了解對應 then()-catchError()-whenComplete();
await _function04();
_function04(index) async {
switch (index) {
case 1:
await Future.error(ArgumentError.notNull('Input')).catchError((val) => print('Function04 -> $val'));
break;
case 2:
try {
await Future.error(ArgumentError.notNull('Input'));
} catch (e) {
print('Function04 -> catch -> $e');
} finally {
print('Function04 -> Finally!');
}
break;
}
}
(f.) 針對多個 Future 嵌套導緻的 Callback hell,async-await 處理方式要簡潔一些;
await _functionThen();
_functionThen() async {
await _itemThen01();
}
_itemThen01() async {
await Future.delayed(Duration(seconds: 3), () {
print('Future -> then(1) -> Future.delayed 3s!');
return _itemThen02();
});
}
_itemThen02() async {
await Future.delayed(Duration(seconds: 2), () {
print('Future -> then(2) -> Future.delayed 2s!');
return _itemThen03();
});
}
_itemThen03() async {
await Future.delayed(Duration(seconds: 2), () {
print('Future -> then(3) -> Future.delayed 2s!');
return 'Future.delayed 2s!';
}).whenComplete(() => print('Future whenComplete!'));
}
小擴充
小菜在嘗試 async-await 時還遇到 async,小菜在 bloc 狀态管理時使用時都是 async 和 Stream,小菜簡單了解一下相關差異;
async*
async 也可以用于異步,方法前使用 async 關鍵字可以将該方法标記為異步生成器,傳回的是一個 Stream 對象,使用 yield 語句來傳遞值;
對于 Stream 的使用,小菜之前有基本的了解,一般通過 skin 添加資料,通過 listen 進行資料監聽;
yield 關鍵字會向 async* 聲明的一步生成器的輸出流添加一個值,有點類似 return,但不會終止函數;
_function06() async* {
for (int i = 1; i <= 10; i++) {
await Future.delayed(const Duration(seconds: 1));
yield i;
}
}
await for (int num in _function06()) {
print('current num = $num');
}
_function06().listen((num) => print('current num = $num'));
小菜對 Dart 異步的認知還不完全,接下來會繼續嘗試 isolate 以及 EventLoop 執行順序等;如有錯誤和遺漏請多多指導!
來源: 阿策小和尚