摘要:包含所有外來的事件,,,,之間的等。當(dāng)定義函數(shù)時,還可以指定其運行結(jié)果返回值的類型,以提高代碼的可讀性定義了返回結(jié)果值為類型因為類型不匹配,會報錯最主要的功能就是提供了鏈?zhǔn)秸{(diào)用。
由于前面的HTTP請求用到了異步操作,不少小伙伴都被這個問題折了下腰,今天總結(jié)分享下實戰(zhàn)成果。Dart是一個單線程的語言,遇到有延遲的運算(比如IO操作、延時執(zhí)行)時,線程中按順序執(zhí)行的運算就會阻塞,用戶就會感覺到卡頓,于是通常用異步處理來解決這個問題。當(dāng)遇到有需要延遲的運算(async)時,將其放入到延遲運算的隊列(await)中去,把不需要延遲運算的部分先執(zhí)行掉,最后再來處理延遲運算的部分。
async和await首先看一個案例:
//HTTP的get請求返回值為Future類型,即其返回值未來是一個String類型的值 getData() async { //async關(guān)鍵字聲明該函數(shù)內(nèi)部有代碼需要延遲執(zhí)行 return await http.get(Uri.encodeFull(url), headers: {"Accept": "application/json"}); //await關(guān)鍵字聲明運算為延遲執(zhí)行,然后return運算結(jié)果 }
然后我們調(diào)用這個函數(shù),想獲取其結(jié)果:
String data = getData();
在書寫時,在IDE中這個代碼是沒有問題的,但是當(dāng)我們運行這段代碼時,就報錯了:
為什么呢?因為data是String類型,而函數(shù)getData()是一個異步操作函數(shù),其返回值是一個await延遲執(zhí)行的結(jié)果。在Dart中,有await標(biāo)記的運算,其結(jié)果值都是一個Future對象,Future不是String類型,所以就報錯了。
那如果這樣的話,我們就沒法獲取到延遲執(zhí)行的結(jié)果了?當(dāng)然可以,Dart規(guī)定有async標(biāo)記的函數(shù),只能由await來調(diào)用,比如這樣:
String data = await getData();
但是要使用await,必須在有async標(biāo)記的函數(shù)中運行,否則這個await會報錯:
于是,我們要為這個給data賦值的語句加一個async函數(shù)的包裝:
String data; setData() async { data = await getData(); //getData()延遲執(zhí)行后賦值給data }
上面這種方法一般用于調(diào)用封裝好的異步接口,比如getData()被封裝到了其他dart文件,通過使用async函數(shù)對其調(diào)取使用
再或者,我們?nèi)サ?b>async函數(shù)的包裝,在getData()中直接完成data變量的賦值:
String data; getData() async { data = await http.get(Uri.encodeFull(url), headers: {"Accept": "application/json"}); //延遲執(zhí)行后賦值給data }
這樣,data就獲取到HTTP請求的數(shù)據(jù)了。就這樣就完了?是滴,只要記住兩點:
await關(guān)鍵字必須在async函數(shù)內(nèi)部使用
調(diào)用async函數(shù)必須使用await關(guān)鍵字
PS:await關(guān)鍵字真的很形象,等一等的意思,就是說,既然你運行的時候都要等一等,那我調(diào)用的時候也等一等吧Future簡單科普
前面?zhèn)€講到過,直接return await ...的時候,實際上返回的是一個延遲計算的Future對象,這個Future對象是Dart內(nèi)置的,有自己的隊列策略,我們就來聊聊這個Future。
先啰嗦一些關(guān)于Dart在線程方面的知識。
Dart是基于單線程模型的語言。在Dart也有自己的進程(或者叫線程)機制,名叫isolate。APP的啟動入口main函數(shù)就是一個isolate。玩家也可以通過引入import "dart:isolate"創(chuàng)建自己的isolate,對多核CPU的特性來說,多個isolate可以顯著提高運算效率,當(dāng)然也要適當(dāng)控制isolate的數(shù)量,不應(yīng)濫用,否則走火入魔自廢武功。有一個很重要的點,Dart中isolate之間無法直接共享內(nèi)存,不同的isolate之間只能通過isolate API進行通信,當(dāng)然本篇的重點在于Future,不展開講isolate,心急的小伙伴可以參考官方閱讀理解或者參考大神tain335的人肉翻譯。
Dart線程中有一個消息循環(huán)機制(event loop)和兩個隊列(event queue和microtask queue)。
event queue包含所有外來的事件:I/O,mouse events,drawing events,timers,isolate之間的message等。任意isolate中新增的event(I/O,mouse events,drawing events,timers,isolate的message)都會放入event queue中排隊等待執(zhí)行,好比機場的公共排隊大廳。
microtask queue只在當(dāng)前isolate的任務(wù)隊列中排隊,優(yōu)先級高于event queue,好比機場里的某個VIP候機室,總是VIP用戶先登機了,才開放公共排隊入口。
如果在event中插入microtask,當(dāng)前event執(zhí)行完畢即可插隊執(zhí)行microtask。如果沒有microtask,就沒辦法插隊了,也就是說,microtask queue的存在為Dart提供了給任務(wù)隊列插隊的解決方案。
當(dāng)main方法執(zhí)行完畢退出后,event loop就會以FIFO(先進先出)的順序執(zhí)行microtask,當(dāng)所有microtask執(zhí)行完后它會從event queue中取事件并執(zhí)行。如此反復(fù),直到兩個隊列都為空,如下流程圖:
注意:當(dāng)事件循環(huán)正在處理microtask的時候,event queue會被堵塞。這時候app就無法進行UI繪制,響應(yīng)鼠標(biāo)事件和I/O等事件。胡亂插隊也是有代價的~
雖然你可以預(yù)測任務(wù)執(zhí)行的順序,但你無法準(zhǔn)確的預(yù)測到事件循環(huán)何時會處理你期望的任務(wù)。例如當(dāng)你創(chuàng)建一個延時1s的任務(wù),但在排在你之前的任務(wù)結(jié)束前事件循環(huán)是不會處理這個延時任務(wù)的,也就是或任務(wù)執(zhí)行可能是大于1s的。
OK,了解以上信息之后,再來回到Future,小伙伴可能已經(jīng)被繞暈了。
Future就是event,很多Flutter內(nèi)置的組件比如前幾篇用到的Http(http請求控件)的get函數(shù)、RefreshIndicator(下拉手勢刷新控件)的onRefresh函數(shù)都是event。每一個被await標(biāo)記的句柄也是一個event,每創(chuàng)建一個Future就會把這個Future扔進event queue中排隊等候安檢~
什么?那microtask呢?當(dāng)然不會忘了這個,scheduleMicrotask,用法和Future基本一樣。
為什么要用Future?前面講到,用async和await組合,即可向event queue中插入event實現(xiàn)異步操作,好像Future的存在有些多余的感覺,剛開始我本人也有這樣的疑惑,且往下看。
當(dāng)定義Flutter函數(shù)時,還可以指定其運行結(jié)果返回值的類型,以提高代碼的可讀性:
//定義了返回結(jié)果值為String類型 FuturegetDatas(String category) async { var request = await _httpClient.getUrl(Uri.parse(url)); var response = await request.close(); return await response.transform(utf8.decoder).join(); } run() async{ int data = await getDatas("keji"); //因為類型不匹配,IDE會報錯 }
Future最主要的功能就是提供了鏈?zhǔn)秸{(diào)用。熟悉ES6語法的小伙伴樂開了花,鏈?zhǔn)秸{(diào)用解決兩大問題:明確代碼執(zhí)行的依賴關(guān)系和實現(xiàn)異常捕獲。WTF?還不明白?且看下面這些案例:
//案例1 funA() async{ ...set an important variable... } funB() async{ await funA(); ...use the important variable... } main() async { funB(); } //如果要想先執(zhí)行funA再執(zhí)行funB,必須在funB中await funA(); //funB的代碼與funA耦合,將來如果funA廢掉或者改動,funB中還需要經(jīng)過修改以適配變更。 //案例2 funA() async{ try{ ...set an important variable... }catch(e){ do sth... }finally{ do sth. else... } } funB() async{ try{ ...use the important variable... }catch(e){ do sth... }finally{ do sth. else... } } main() async { await funA(); await funB(); } //沒有明確體現(xiàn)出設(shè)置變量和使用變量之間的依賴關(guān)系,其他開發(fā)者難以理解你的代碼邏輯,代碼維護困難 //并且如果為了防止funA()或者funB()因發(fā)生異常導(dǎo)致程序崩潰 //要到funA()或者funB()中分別加入`try`、`catch`、`finally`
為了解決上面的問題,Future提供了一套非常簡潔的解決方案:
//案例3 funA(){ ...set an important variable... //設(shè)置變量 } funB(){ ...use the important variable... //使用變量 } main(){ new Future.then(funA()).then(funB()); // 明確表現(xiàn)出了后者依賴前者設(shè)置的變量值 new Future.then(funA()).then((_) {new Future(funB())}); //還可以這樣用 //鏈?zhǔn)秸{(diào)用,捕獲異常 new Future.then(funA(),onError: (e) { handleError(e); }).then(funB(),onError: (e) { handleError(e); }) }
案例3的玩法是async和await無法企及的,因此掌握Future還是很有必要滴。當(dāng)然了,Future的玩法不僅僅局限于案例3,還有很多有趣的玩法,包括和microtask對象scheduleMicrotask配合使用,我這里就不一一介紹了,大家參考大神tain335的人肉翻譯或者官網(wǎng)閱讀理解吧。
總結(jié)Dart的isolate中加入了event queue和microtask queue后,有了一點協(xié)程的感覺,或許這就是Flutter為啥在性能上敢和原生開發(fā)叫板的原因之一吧。本篇的內(nèi)容比較抽象,如果還是有不明白的小伙伴,歡迎留言提問,我盡量回答,哈哈哈,就醬,歡迎加入到Flutter圈子或flutter 中文社區(qū)(官方QQ群:338252156),群里有前后端及全棧各路大神鎮(zhèn)場子,加入進來沒事就寫寫APP掙點外快(這個真的有),順便翻譯翻譯官方英文原稿拉一票粉絲,一舉多得何樂而不為呢。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/94250.html
摘要:中的的線程是以事件循環(huán)和消息隊列的形式存在,包含兩個任務(wù)隊列,一個是內(nèi)部隊列,一個是外部隊列,而的優(yōu)先級又高于。同時還有處理按住時的事件額外處理,同時手勢處理一般在的子類進行。谷歌大會之后,有不少人咨詢了我 Flutter 相關(guān)的問題,其中有不少是和面試相關(guān)的,如今一些招聘上也開始羅列 Flutter 相關(guān)要求,最后想了想還是寫一期總結(jié)吧,也算是 Flutter 的階段復(fù)習(xí)。 ??系統(tǒng)完...
摘要:上一篇我們實現(xiàn)了新聞列表,但在網(wǎng)絡(luò)不好的時候列表會白屏,因此為了提高使用體驗,往列表中加入懶加載效果。其次,引入一個內(nèi)置的手勢控件,用于支持下拉刷新列表的效果如下圖將異步執(zhí)行也進行了控件化處理,即。 上一篇我們實現(xiàn)了新聞列表,但在網(wǎng)絡(luò)不好的時候列表會白屏,因此為了提高使用體驗,往列表中加入懶加載效果。其次,引入一個Flutter內(nèi)置的手勢控件,用于支持下拉刷新列表的效果如下圖: sho...
閱讀 2793·2021-11-11 16:54
閱讀 3879·2021-08-16 10:46
閱讀 3586·2019-08-30 14:18
閱讀 3176·2019-08-30 14:01
閱讀 2873·2019-08-29 14:15
閱讀 2181·2019-08-29 11:31
閱讀 3231·2019-08-29 11:05
閱讀 2743·2019-08-26 11:54