Flutter--Future原理

Flutter--Future

什么是Future?

簡單來說future就是一個(gè)Future<T>對象,當(dāng)執(zhí)行return await嚷闭。。赖临。的時(shí)候胞锰,實(shí)際上返回的是一個(gè)延遲計(jì)算的Future對象,這個(gè)Future對象是Dart內(nèi)置的兢榨,有自己的隊(duì)列策略嗅榕,它將要操作的事件放入EventQueue中,在隊(duì)列中的事件按照先進(jìn)先出的原則去逐一處理事件吵聪,當(dāng)事件處理完成后凌那,將結(jié)果返回給Future對象。

在這個(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í)候會報(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對象琅绅,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都是隔離的卧抗,并不會共享內(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í),才會去執(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過于龐大漠畜,否則會阻塞其他事件的處理

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í)瘾敢,才會延遲1s執(zhí)行拍冠,否則等待的時(shí)間會比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í)行完成了,則會創(chuàng)建一個(gè)task碟摆,將該task的添加到microtask queue中晃财,并且該任務(wù)將會執(zhí)行通過then傳入的函數(shù)
  3. Future只是創(chuàng)建了一個(gè)Event,將Event插入到了Event Queue的隊(duì)尾
  4. 使用Future.value構(gòu)造函數(shù)的時(shí)候典蜕,就會和第二條一樣断盛,創(chuàng)建Task丟到microtask Queue中執(zhí)行then傳入的函數(shù)
  5. Future.sync構(gòu)造函數(shù)執(zhí)行了它傳入的函數(shù)之后,也會立即創(chuàng)建Task丟到microtask Queue中執(zhí)行

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末愉舔,一起剝皮案震驚了整個(gè)濱河市钢猛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌屑宠,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仇让,死亡現(xiàn)場離奇詭異典奉,居然都是意外死亡躺翻,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門卫玖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來公你,“玉大人,你說我怎么就攤上這事假瞬∩驴浚” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵脱茉,是天一觀的道長剪芥。 經(jīng)常有香客問我,道長琴许,這世上最難降的妖魔是什么税肪? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮榜田,結(jié)果婚禮上益兄,老公的妹妹穿的比我還像新娘。我一直安慰自己箭券,他們只是感情好净捅,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蛔六,像睡著了一般。 火紅的嫁衣襯著肌膚如雪庆捺。 梳的紋絲不亂的頭發(fā)上古今,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天滔以,我揣著相機(jī)與錄音捉腥,去河邊找鬼抵碟。 笑死,一個(gè)胖子當(dāng)著我的面吹牛敦迄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼罚屋,長吁一口氣:“原來是場噩夢啊……” “哼脾猛!你這毒婦竟也來了撕彤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤猛拴,失蹤者是張志新(化名)和其女友劉穎羹铅,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體愉昆,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡职员,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了撼唾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片廉邑。...
    茶點(diǎn)故事閱讀 38,617評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖倒谷,靈堂內(nèi)的尸體忽然破棺而出蛛蒙,到底是詐尸還是另有隱情,我是刑警寧澤渤愁,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布牵祟,位于F島的核電站,受9級特大地震影響抖格,放射性物質(zhì)發(fā)生泄漏诺苹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一雹拄、第九天 我趴在偏房一處隱蔽的房頂上張望收奔。 院中可真熱鬧,春花似錦滓玖、人聲如沸坪哄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翩肌。三九已至,卻和暖如春禁悠,著一層夾襖步出監(jiān)牢的瞬間念祭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工碍侦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留粱坤,地道東北人隶糕。 一個(gè)月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像站玄,于是被迫代替她去往敵國和親若厚。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評論 2 348