Flutter--Future
什么是Future?
簡單來說future就是一個(gè)Future<T>對(duì)象,當(dāng)執(zhí)行return await。。。的時(shí)候,實(shí)際上返回的是一個(gè)延遲計(jì)算的Future對(duì)象,這個(gè)Future對(duì)象是Dart內(nèi)置的,有自己的隊(duì)列策略,它將要操作的事件放入EventQueue中,在隊(duì)列中的事件按照先進(jìn)先出的原則去逐一處理事件,當(dāng)事件處理完成后,將結(jié)果返回給Future對(duì)象。
在這個(gè)過程中涉及到了異步和等待:
- 異步:就是不用阻塞當(dāng)前線程,來等待該線程任務(wù)處理完成再去執(zhí)行其他任務(wù)。
- 等待:await,聲明運(yùn)算為延遲執(zhí)行
async和await
首先看一個(gè)例子:
getData() async{
return await http.get(Uri.encodeFull(url), headers: {"Accept": "application/json"});
}
//然后調(diào)用函數(shù)來獲取結(jié)果
String data = getData();
這段代碼在運(yùn)行的時(shí)候會(huì)報(bào)錯(cuò)。
因?yàn)?code>data是String類型,而函數(shù)getData()是一個(gè)異步操作函數(shù),其返回值是一個(gè)await延遲執(zhí)行的結(jié)果。
在Dart中,有await標(biāo)記的運(yùn)算,結(jié)果都是一個(gè)Future對(duì)象,Future不是String類型,所以就報(bào)錯(cuò)了。
如何獲取異步函數(shù)的結(jié)果呢?Dart規(guī)定有async標(biāo)記的函數(shù),只能由await來調(diào)用,那么我們可以在函數(shù)前加一個(gè)await關(guān)鍵字:
String data = await getData();
但是這違背了await必須要在async標(biāo)記的函數(shù)中使用,所以賦值代碼可以改成:
String data;
setData() async {
data = await getData(); //getData()延遲執(zhí)行后賦值給data
}
總結(jié):
async和await的使用其實(shí)就只有兩點(diǎn):
-
await關(guān)鍵字必須在async函數(shù)內(nèi)部使用 - 調(diào)用
async函數(shù)必須使用await關(guān)鍵字
Dart異步
Dart是單線程模型,是一種Event-Looper以及Event-Queue的模型,所有的事件都是通過EventLooper的依次執(zhí)行。
Event Loop的執(zhí)行順序
- 從EventQueue中獲取Event
-
處理Event直到EventQueue為空
Event即事件,包括輸入,點(diǎn)擊,Timer,文件IO等
單線程模型
所謂單線程,就是一旦一個(gè)函數(shù)開始執(zhí)行,就必須將這個(gè)函數(shù)執(zhí)行完,才能去執(zhí)行其他函數(shù)。
Dart中沒有線程的概念,只有isolate,每個(gè)isolate都是隔離的,并不會(huì)共享內(nèi)存。一個(gè)Dart程序是在Main isolate中的main函數(shù)開始,而在Main函數(shù)結(jié)束后,Main isolate線程開始一個(gè)個(gè)(one by one)的處理Event Queue中的每一個(gè)Event。

Event Queue、Microtask Queue
Dart中的Main Isolate只有一個(gè)Event Looper,但是存在兩個(gè)Event Queue:
- Event Queue
-
Microtask Queue
這兩者之間的關(guān)系可以用一張圖來說明:
- Microtask Queue中的Event優(yōu)先被處理
- 直到Microtask Queue隊(duì)列中的Event為空時(shí),才會(huì)去執(zhí)行Event Queue中的Event
異步任務(wù)調(diào)度
當(dāng)有代碼可以在后續(xù)任務(wù)執(zhí)行的時(shí)候,有兩種方式,通過dart:async這個(gè)Lib中的API即可:
- 使用Future類,可以將任務(wù)加入到Event Queue的隊(duì)尾
- 使用scheduleMicrotask函數(shù),將任務(wù)加入到Microtask Queue隊(duì)尾
當(dāng)使用EventQueue時(shí),需要考慮清楚,盡量避免microtask queue過于龐大,否則會(huì)阻塞其他事件的處理

Future的使用
一般常用的Future構(gòu)造函數(shù):
new Future((){
// doing something
});
而一般常用的還有當(dāng)有分治任務(wù)時(shí),需要將一個(gè)大任務(wù)拆成很多小任務(wù)一步步執(zhí)行時(shí),就需要使用到Future.then函數(shù)來拆解任務(wù):
void main(){
new Future(() => futureTask) // 異步任務(wù)的函數(shù)
.then((m) => "futueTask execute result:$m") // 任務(wù)執(zhí)行完后的子任務(wù)
.then((m) => m.length) // 其中m為上個(gè)任務(wù)執(zhí)行完后的返回的結(jié)果
.then((m) => printLength(m))
.whenComplete(() => whenTaskCompelete); // 當(dāng)所有任務(wù)完成后的回調(diào)函數(shù)
}
int futureTask() {
return 21;
}
void printLength(int length) {
print("Text Length:$length");
}
void whenTaskCompelete() {
print("Task Complete");
}
當(dāng)任務(wù)需要延遲執(zhí)行時(shí),可以使用new Future.delay來將任務(wù)延遲執(zhí)行,而如上所述,只有當(dāng)Main isolate的Event Queue處于Idle的狀態(tài)時(shí),才會(huì)延遲1s執(zhí)行,否則等待的時(shí)間會(huì)比1s長很多
new Future.delayed(const Duration(seconds: 1), () => futureTask);
Tips
-
Future中的then并沒有創(chuàng)建新的Event丟到Event Queue中,而只是一個(gè)普通的Function Call,在FutureTask執(zhí)行完后,立即開始執(zhí)行 - 當(dāng)
Future在then函數(shù)先已經(jīng)執(zhí)行完成了,則會(huì)創(chuàng)建一個(gè)task,將該task的添加到microtask queue中,并且該任務(wù)將會(huì)執(zhí)行通過then傳入的函數(shù) -
Future只是創(chuàng)建了一個(gè)Event,將Event插入到了Event Queue的隊(duì)尾 - 使用
Future.value構(gòu)造函數(shù)的時(shí)候,就會(huì)和第二條一樣,創(chuàng)建Task丟到microtask Queue中執(zhí)行then傳入的函數(shù) -
Future.sync構(gòu)造函數(shù)執(zhí)行了它傳入的函數(shù)之后,也會(huì)立即創(chuàng)建Task丟到microtask Queue中執(zhí)行
關(guān)于Future的原理基本就到這里了~~~


