【Flutter】Future, async, await

Dart 為單線程語言,但它提供了異步編程的方式,Future, async, await 為異步編程的類和關(guān)鍵字,
Future
Future.then
異步編程最常用的場景是訪問網(wǎng)絡(luò)接口,返回數(shù)據(jù),這里我們模擬這樣的場景,2秒后返回網(wǎng)絡(luò)數(shù)據(jù),代碼如下:
Future<String> getMyName() {
Future.delayed(Duration(seconds: 2), () => '老孟');
}
下面將獲取到的數(shù)據(jù)打印出來,
void _incrementCounter() {
var name = getMyName();
print('name:$name');
}
上面的用法是典型的錯誤用法,而且也是大部分初學(xué)者容易犯錯的地方,getMyName 為 Future 方法,表示此方法為異步方法。
上面的代碼打印日志如下:
flutter: name:Instance of 'Future<String>'
正確的用法如下:
void _incrementCounter() {
getMyName().then((String value) {
print('name:$value');
});
}
2秒后打印日志:
flutter: name:老孟
Future.then.catchError
有這樣一個Future方法:延遲1秒將字符串轉(zhuǎn)換為int類型,代碼如下:
Future<int> parse(String value) {
return Future.delayed(Duration(seconds: 1), () {
return int.parse(value);
});
}
調(diào)用此方法:
parse("2").then((int value) {
print('value:$value');
});
此時可以正確轉(zhuǎn)換,輸出日志:
flutter: value:2
如果入?yún)榉菙?shù)字,則會出現(xiàn)轉(zhuǎn)換異常,代碼如下:
parse("2a").then((int value) {
print('value:$value');
});
運(yùn)行,拋出異常:

此時,需要捕獲異常并做處理,代碼如下:
parse("2a").then((int value) {
print('value:$value');
}).catchError((error){
print('error:$error');
});
輸出日志:
flutter: error:FormatException: Invalid radix-10 number (at character 1)
2a
^
Future 的異常不能使用 try..catch 捕獲。
Future 可以返回任意類型的值,也可以不返回值,
Future<void> futureVoid() {
return Future.delayed(Duration(seconds: 1), () {
//do something
});
}
Future.delayed
延遲處理,上面已經(jīng)多次使用,延遲1秒執(zhí)行:
Future.delayed(Duration(seconds: 1), () {
//do something
});
Future.value
創(chuàng)建一個帶返回值的 Future :
Future<String> futureValue() {
return Future.value('老孟');
}
Future.any
返回[futures]中要完成的第一個Future的結(jié)果,返回的第一個結(jié)果表示已完成,其他Future結(jié)果被拋棄。如果[futures]為空,或者沒有一個Future完成,那么Future永遠(yuǎn)不會完成。
Future<String> futureAny() {
return Future.any([
Future.delayed(Duration(seconds: 1),()=> '1'),
Future.delayed(Duration(seconds: 2),()=> '2'),
Future.delayed(Duration(seconds: 3),()=> '3'),
]);
}
輸出日志:
flutter: value:1
Future.microtask
Flutter 的 main isolate 中有2個隊列:Event Queue 和 Microtask Queue ,這兩個 Queue 區(qū)別是 Microtask Queue執(zhí)行的優(yōu)先級比Event Queue高。
Future.microtask 是向Microtask Queue添加任務(wù),而其他Future 方法是向Event Queue中添加任務(wù)。
Future<String> futureMicrotask() {
return Future.microtask(()=>'老孟');
}
Future.sync
表示Future中代碼是同步執(zhí)行的。
Future<void> futureSync() {
return Future.sync(()=>print('Future.sync'));
}
調(diào)用:
void _incrementCounter() {
print('Future.sync begin');
futureSync();
print('Future.sync end');
}
打印日志:
flutter: Future.sync begin
flutter: Future.sync
flutter: Future.sync end
Future.error
返回異常,可以通過catchError捕獲。
Future<void> futureSync() {
return Future.sync(() => print('Future.sync'));
}
調(diào)用:
futureError().catchError((error) {
print('$error');
});
輸出日志:
flutter: this is error
Future.doWhile
重復(fù)執(zhí)行操作,直到返回 false。
Future<void> futureDoWhile() {
var i = 0;
return Future.doWhile(() {
print('i:$i');
return Future.value(i++ < 10);
});
}
日志輸出:
flutter: i:0
flutter: i:1
flutter: i:2
flutter: i:3
flutter: i:4
flutter: i:5
flutter: i:6
flutter: i:7
flutter: i:8
flutter: i:9
flutter: i:10
Future.forEach
遍歷完所有的值或者拋出異常才變?yōu)橥瓿蔂顟B(tài)。
Future<void> futureForEach() {
return Future.forEach([1,2,3,5],(value){
print('value:$value');
});
}
日志輸出:
flutter: value:1
flutter: value:2
flutter: value:3
flutter: value:5
async, await
async 和 await 關(guān)鍵字允許我們像寫同步代碼一樣寫異步代碼,有如下異步函數(shù):
Future<int> parse(String value) {
return Future.delayed(Duration(seconds: 1), () {
return int.parse(value);
});
}
可以使用如下方法獲取結(jié)果:
void _incrementCounter() {
parse('2').then((value) => print('value:$value'));
}
也可以使用如下方法:
void _incrementCounter() async {
var result = await parse('2');
print('result:$result');
}
日志輸出:
flutter: result:2
使用async 和 await 可讀性更強(qiáng)。
使用 async 修飾的方法返回 Future,是異步方法。
Future<int> toInt(String value) async {
return int.parse(value);
}
async 和 await 的異常捕獲需要使用try..catcch
void _incrementCounter() async {
try{
await parse('1');
}catch(e){
}
}
總結(jié)
async 和 await 關(guān)鍵字可以認(rèn)為是 Future 的語法糖。
async 和 await 關(guān)鍵字可以有效的解決 Future.then 嵌套問題
void _incrementCounter() {
fun1().then((value) {
fun2().then((value) {
fun3().then((value) {});
});
});
}
Future<String> fun1() {
return Future.value('a');
}
Future<String> fun2() {
return Future.value('b');
}
Future<String> fun3() {
return Future.value('c');
}這種地獄嵌套可讀性非常差,使用async 和 await 寫法:
void _incrementCounter() async {
var result1 = await fun1();
var result2 = await fun2();
var result3 = await fun3();
}Future.then 可以使用鏈?zhǔn)秸{(diào)用
void _incrementCounter() async {
fun1()
.then((value) {})
.then((value){});
}

