Flutter--Future原理

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é):
asyncawait的使用其實(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:

  1. Event Queue
  2. 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

  1. Future中的then并沒有創(chuàng)建新的Event丟到Event Queue中,而只是一個(gè)普通的Function Call,在FutureTask執(zhí)行完后,立即開始執(zhí)行
  2. 當(dāng)Futurethen函數(shù)先已經(jīng)執(zhí)行完成了,則會(huì)創(chuàng)建一個(gè)task,將該task的添加到microtask queue中,并且該任務(wù)將會(huì)執(zhí)行通過then傳入的函數(shù)
  3. Future只是創(chuàng)建了一個(gè)Event,將Event插入到了Event Queue的隊(duì)尾
  4. 使用Future.value構(gòu)造函數(shù)的時(shí)候,就會(huì)和第二條一樣,創(chuàng)建Task丟到microtask Queue中執(zhí)行then傳入的函數(shù)
  5. Future.sync構(gòu)造函數(shù)執(zhí)行了它傳入的函數(shù)之后,也會(huì)立即創(chuàng)建Task丟到microtask Queue中執(zhí)行

關(guān)于Future的原理基本就到這里了~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容