由于dart
是一種單線程的語(yǔ)言,在編寫dart代碼時(shí)對(duì)于耗時(shí)操作的處理要使用異步來(lái)進(jìn)行。dart
中自帶有future
渡处,async/await
,Isolate
, stream
和廣播
等異步操作等方式。
Dart
中的事件循環(huán)
在dart
中實(shí)際上有兩種隊(duì)列:
1.事件隊(duì)列(event queue):包含所有的外來(lái)事件:
I/O
,mouse events
,drawing events
,timers
,isolate
之間的信息傳遞2.微任務(wù)隊(duì)列(
microtask queue
):表示一個(gè)短時(shí)間內(nèi)就會(huì)完成的異步任務(wù)铣鹏,它的優(yōu)先級(jí)最高书闸,高于event queue
,只要隊(duì)列中還有任務(wù),就可以一直霸占著事件循環(huán)松蒜。microtask queue
添加的任務(wù)只要是由Dart內(nèi)部產(chǎn)生
dart 事件循環(huán)流程圖
Future異步方式
常見處理耗時(shí)操作的返回值為future
,不會(huì)阻塞當(dāng)前的線程導(dǎo)致程序卡死幢哨。
void testFuture(){
print("FutureTest==開始")
Future((){
return "任務(wù)1";
}).then((value) => print(value+"結(jié)束"));
Future((){
return "任務(wù)2";
}).then((value) => print(value+"結(jié)束"));
Future((){
sleep(Duration(seconds: 1));
return "任務(wù)3";
}).then((value) => print(value+"結(jié)束"));
Future((){
return "任務(wù)4";
}).then((value) => print(value+"結(jié)束"));
Future((){
return "任務(wù)5";
}).then((value) => print(value+"結(jié)束"));
print("FutureTest==結(jié)束")
}
//打印結(jié)果雄人,輸出不會(huì)阻塞當(dāng)前線程
FutureTest==開始
FutureTest==結(jié)束
任務(wù)1結(jié)束
任務(wù)2結(jié)束
任務(wù)3結(jié)束
任務(wù)4結(jié)束
任務(wù)5結(jié)束
在future執(zhí)行過程中僚纷,future執(zhí)行的順序和添加的順序是一致的矩距,上一個(gè)任務(wù)執(zhí)行完成才會(huì)執(zhí)行下一個(gè)future,在OC/Swift多線程中這些返回的順序是不定的怖竭。
void testFuture1(){
//future的執(zhí)行順序和添加順序有關(guān)锥债,在future中 then的比f(wàn)uture的默認(rèn)優(yōu)先級(jí)要高,執(zhí)行完了future直接執(zhí)行then
Future((){
return "任務(wù)1";
}).then((value) => print(value+"結(jié)束"));
Future x = Future((){
return "任務(wù)2";
})
Future((){
return "任務(wù)3";
}).then((value) => print(value+"結(jié)束"));
Future((){
return "任務(wù)4";
}).then((value) => print(value+"結(jié)束"));
Future((){
return "任務(wù)5";
}).then((value) => print(value+"結(jié)束"));
x.then((value)=>print(value+"結(jié)束"));
}
//執(zhí)行結(jié)果
任務(wù)1結(jié)束
任務(wù)2結(jié)束
任務(wù)3結(jié)束
任務(wù)4結(jié)束
任務(wù)5結(jié)束
future執(zhí)行完成返回的是一個(gè)future對(duì)象痊臭,使用then()方法注冊(cè)一個(gè)回調(diào)赞弥,F(xiàn)uture->then->Complete認(rèn)為是一個(gè)任務(wù),這個(gè)任務(wù)處理完成了才能繼續(xù)處理其他的任務(wù),future執(zhí)行任務(wù)中可以對(duì)error和complete事件做一個(gè)處理趣兄。
Future((){
throw "發(fā)生錯(cuò)誤了";
return "你好";
}).then((value) => print("我就是value"))
.catchError((error)=>print("當(dāng)前error==$error"))
.whenComplete(() => print("當(dāng)前事件結(jié)束了"));
對(duì)于Future
來(lái)說(shuō)绽左,異步處理成功了就執(zhí)行成功的操作,異步處理失敗了就捕獲錯(cuò)誤或者停止后續(xù)操作艇潭。一個(gè)Future
只會(huì)對(duì)應(yīng)一個(gè)結(jié)果拼窥,要么成功,要么失敗蹋凝。Future.catchError
回調(diào)只處理原始Future
拋出的錯(cuò)誤鲁纠,不能處理回調(diào)函數(shù)拋出的錯(cuò)誤,onError只能處理當(dāng)前Future的錯(cuò)誤,Future.whenComplete
在Future完成之后總是會(huì)調(diào)用鳍寂,不管是錯(cuò)誤導(dǎo)致的完成還是正常執(zhí)行完畢改含。比如在網(wǎng)絡(luò)請(qǐng)求前彈出加載對(duì)話框,在請(qǐng)求結(jié)束后關(guān)閉對(duì)話框迄汛。并且返回一個(gè)Future對(duì)象.
請(qǐng)記住捍壤,Future
的所有API
的返回值仍然是一個(gè)Future
對(duì)象,所以可以很方便的進(jìn)行鏈?zhǔn)秸{(diào)用鞍爱。
微任務(wù), 使用scheduleMicrotask()
來(lái)創(chuàng)建一個(gè)微任務(wù)鹃觉,優(yōu)先級(jí)要比Future要高
//多種相互組合
void complexEventLoop(){
print("開始執(zhí)行");
Future(()=>"1").then((value) => print("$value==結(jié)束"));
var x = Future(()=>"2");
var y = Future(()=> "6");
y.then((value) => print("$value==結(jié)束"));
x.then((value){
print("$value==結(jié)束");
scheduleMicrotask((){
print("4==結(jié)束");
});
}).then((value) => print("3==結(jié)束"));
scheduleMicrotask((){
//微任務(wù)隊(duì)列
print("7==結(jié)束");
});
Future(()=> "5").then((value) => print("$value==結(jié)束"));
print("結(jié)束執(zhí)行");
}
//輸出值
開始執(zhí)行
結(jié)束執(zhí)行
7==結(jié)束
1==結(jié)束
2==結(jié)束
3==結(jié)束
4==結(jié)束
6==結(jié)束
5==結(jié)束
結(jié)果分析
1.開始執(zhí)行和結(jié)束執(zhí)行是同步的,會(huì)按照順序輸出
2.任務(wù)7 是微任務(wù)優(yōu)先級(jí)最高睹逃,第一個(gè)輸出
3.接著按著Future加入的順序開始執(zhí)行 1 2
4.執(zhí)行到2結(jié)束的時(shí)候then中有一個(gè)微任務(wù)盗扇,但是改Future任務(wù)還沒有結(jié)束,會(huì)繼續(xù)執(zhí)行該任務(wù)輸出3
5.任務(wù)3輸出完成開始執(zhí)行微任務(wù) 輸出4
6.任務(wù)6對(duì)應(yīng)的Future先執(zhí)行沉填,輸出6
7.最后輸出5
Future提供了幾種方法實(shí)現(xiàn)
Future.value()
疗隶,創(chuàng)建返回指定value的future
Future.value(1).then((value)=>print(value));
//輸出值
1
Future.delayed()
創(chuàng)建一個(gè)延遲執(zhí)行的future
Future.delayed(Duration(seconds: 1)).then((value) => print("延遲執(zhí)行"));
//輸出值
延遲執(zhí)行
Future.then() 用來(lái)注冊(cè)一個(gè)Future
完成時(shí)要調(diào)用的回調(diào)。如果 Future
有多個(gè)then
翼闹,它們也會(huì)按照鏈接的先后順序同步執(zhí)行斑鼻,同時(shí)也會(huì)共用一個(gè)event loop
。
Future((){
return "任務(wù)5";
}).then((value) => print(value+"結(jié)束"));
Future.timeout
,超時(shí)會(huì)拋出TimeoutException異常處理
Future.delayed(new Duration(seconds: 2), () {
return 1;
}).timeout(new Duration(seconds:1)).then(print).catchError(print);
Future.foreach
橄碾,根據(jù)某個(gè)集合創(chuàng)建一系列的Future卵沉,并且按著順序執(zhí)行這些Future颠锉,
Future.forEach({1,2,3}, (num){
return Future.delayed(Duration(seconds: num),(){print("第$num秒執(zhí)行");});
});
Future.wait()
,等待多個(gè)Future任務(wù)完成,
- 所有的future都有正常結(jié)果返回史汗,使用then監(jiān)聽的方法獲的是一個(gè)結(jié)果的集合琼掠,
- 其中一個(gè)或者多個(gè)Future發(fā)生錯(cuò)誤,產(chǎn)生error停撞,則Future返回的結(jié)果就是第一個(gè)發(fā)生錯(cuò)誤的Future的值
void testFuture4() async {
var future1 = new Future.delayed(new Duration(seconds: 1), () => 1);
var future2 = new Future.delayed(new Duration(seconds: 2), () {
return 5;
});
var future3 = new Future.delayed(new Duration(seconds: 3), () => 3);
Future.wait([future1,future2,future3]).then((value) =>print(value))
.catchError((error)=>print(error));
}
//輸出值
[1, 5, 3]
void testFuture5() async {
var future1 = new Future.delayed(new Duration(seconds: 1), () => 1);
var future2 = new Future.delayed(new Duration(seconds: 2), () {
throw 'Future 發(fā)生錯(cuò)誤啦!';
});
var future3 = new Future.delayed(new Duration(seconds: 3), () => 3);
Future.wait([future1,future2,future3]).then((value) =>print(value))
.catchError((error)=>print(error));
}
//輸出值
Future 發(fā)生錯(cuò)誤啦!
Future.any
,返回的是第一個(gè)執(zhí)行完成的Future的結(jié)果瓷蛙,不管結(jié)果是正確還是錯(cuò)誤
Future
.any([1, 2, 5].map((delay) => new Future.delayed(new Duration(seconds: delay), () => delay)))
.then(print)
.catchError(print);
}
///輸出值
1
Future.doWhile ,重復(fù)執(zhí)行某一個(gè)動(dòng)作,直到返回false或者future戈毒,退出循環(huán)艰猬,適用一些遞歸的操作
var random = new Random();
var totalDelay = 0;
Future.doWhile(() {
if (totalDelay > 10) {
print('total delay: $totalDelay seconds');
return false;
}
var delay = random.nextInt(5) + 1;
totalDelay += delay;
return new Future.delayed(new Duration(seconds: delay), () {
print('waited $delay seconds');
return true;
});
}).then(print).catchError(print);
Future.sync
同步執(zhí)行,然后調(diào)度到microtask queue來(lái)完成自己埋市,也就是一個(gè)阻塞任務(wù)冠桃,會(huì)阻塞當(dāng)前線程,sync執(zhí)行完成了之后代碼才會(huì)走到下一行
void testFuture() async {
Future((){
print("Future event 1");
});
Future.sync(() {
print("Future sync event 2");
});
Future((){
print("Future event 3");
});
Future.microtask((){
print("microtask event");
});
}
//輸出值
Future sync event 2
microtask event
Future event 1
Future event 3
如果在sync中返回一個(gè)future,執(zhí)行順序也會(huì)發(fā)生改變道宅。
void testFuture() async {
Future((){
print("Future event 1");
});
Future.sync(() {
return Future(() => print("sync Future event 2"));
});
Future((){
print("Future event 3");
});
Future.microtask((){
print("microtask event");
});
}
//輸出值
microtask event
Future event 1
sync Future event 2
Future event 3
Future.microtask
創(chuàng)建一個(gè)在microtask queue運(yùn)行的Future食听。
microtask queue
的優(yōu)先級(jí)要比event queue
高,而一般Future是在event queue
執(zhí)行的污茵,所以Future.microtask創(chuàng)建的Future會(huì)優(yōu)先于其他的Future執(zhí)行:
void testFuture() async {
Future((){
print("Future event 1");
});
Future((){
print("Future event 2");
});
Future.microtask((){
print("microtask event");
});
}
///輸出值
microtask event
Future event 1
Future event 2
async/await
默認(rèn)future是異步執(zhí)行的樱报,如果想要future同步執(zhí)行,可以通過async/await關(guān)鍵字:
void textAsyncAwait() async{
String valuel = await Future((){
return "這是就是value";
});
print("當(dāng)前value===$valuel");
print("函數(shù)執(zhí)行完畢");
}
//輸出值
當(dāng)前value===這是就是value
函數(shù)執(zhí)行完畢
可以看到Future已經(jīng)開始同步執(zhí)行了泞当,await會(huì)等待Future執(zhí)行結(jié)束后才會(huì)繼續(xù)執(zhí)行后面的代碼迹蛤,
關(guān)鍵字async/await 是dart異步支持的一部分,是一個(gè)語(yǔ)法糖襟士,編譯器或解釋器最終都會(huì)將其轉(zhuǎn)化為一個(gè)Promise(Future)的調(diào)用鏈
- async: 用來(lái)表示函數(shù)時(shí)異步的盗飒,定義的函數(shù)會(huì)返回一個(gè)Future對(duì)象
- await:后面跟著一個(gè)Future,表示等待該異步任務(wù)完成敌蜂,異步任務(wù)完成后才會(huì)繼續(xù)往下執(zhí)行箩兽。await只能出現(xiàn)在異步函數(shù)內(nèi)部,能夠讓我們可以像寫同步代碼一樣來(lái)執(zhí)行異步任務(wù)章喉。
最后 Future的實(shí)現(xiàn),
查看future的源碼會(huì)發(fā)現(xiàn)身坐,異步任務(wù)是基于timer實(shí)現(xiàn)的,定時(shí)器設(shè)置的時(shí)間間隔為zero秸脱,result返回值then進(jìn)行回調(diào)注冊(cè)拿到執(zhí)行之后的結(jié)果 ,有興趣的朋友可以更深層的探究一下
factory Future(FutureOr<T> computation()) {
_Future<T> result = new _Future<T>();
Timer.run(() {
try {
result._complete(computation());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
});
return result;
}
正在學(xué)習(xí)dart中部蛇,如有不足或錯(cuò)誤的地方摊唇,歡迎指正。