什么是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