国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

flutter實(shí)戰(zhàn)5:異步async、await和Future的使用技巧

CatalpaFlat / 2873人閱讀

摘要:包含所有外來(lái)的事件,,,,之間的等。當(dāng)定義函數(shù)時(shí),還可以指定其運(yùn)行結(jié)果返回值的類(lèi)型,以提高代碼的可讀性定義了返回結(jié)果值為類(lèi)型因?yàn)轭?lèi)型不匹配,會(huì)報(bào)錯(cuò)最主要的功能就是提供了鏈?zhǔn)秸{(diào)用。

由于前面的HTTP請(qǐng)求用到了異步操作,不少小伙伴都被這個(gè)問(wèn)題折了下腰,今天總結(jié)分享下實(shí)戰(zhàn)成果。Dart是一個(gè)單線程的語(yǔ)言,遇到有延遲的運(yùn)算(比如IO操作、延時(shí)執(zhí)行)時(shí),線程中按順序執(zhí)行的運(yùn)算就會(huì)阻塞,用戶就會(huì)感覺(jué)到卡頓,于是通常用異步處理來(lái)解決這個(gè)問(wèn)題。當(dāng)遇到有需要延遲的運(yùn)算(async)時(shí),將其放入到延遲運(yùn)算的隊(duì)列(await)中去,把不需要延遲運(yùn)算的部分先執(zhí)行掉,最后再來(lái)處理延遲運(yùn)算的部分。

async和await

首先看一個(gè)案例:

  //HTTP的get請(qǐng)求返回值為Future類(lèi)型,即其返回值未來(lái)是一個(gè)String類(lèi)型的值
  getData() async {    //async關(guān)鍵字聲明該函數(shù)內(nèi)部有代碼需要延遲執(zhí)行
    return await http.get(Uri.encodeFull(url), headers: {"Accept": "application/json"}); //await關(guān)鍵字聲明運(yùn)算為延遲執(zhí)行,然后return運(yùn)算結(jié)果
  }

然后我們調(diào)用這個(gè)函數(shù),想獲取其結(jié)果:

  String data = getData();

在書(shū)寫(xiě)時(shí),在IDE中這個(gè)代碼是沒(méi)有問(wèn)題的,但是當(dāng)我們運(yùn)行這段代碼時(shí),就報(bào)錯(cuò)了:

為什么呢?因?yàn)?b>data是String類(lèi)型,而函數(shù)getData()是一個(gè)異步操作函數(shù),其返回值是一個(gè)await延遲執(zhí)行的結(jié)果。在Dart中,有await標(biāo)記的運(yùn)算,其結(jié)果值都是一個(gè)Future對(duì)象,Future不是String類(lèi)型,所以就報(bào)錯(cuò)了。

那如果這樣的話,我們就沒(méi)法獲取到延遲執(zhí)行的結(jié)果了?當(dāng)然可以,Dart規(guī)定有async標(biāo)記的函數(shù),只能由await來(lái)調(diào)用,比如這樣:

String data = await getData();

但是要使用await,必須在有async標(biāo)記的函數(shù)中運(yùn)行,否則這個(gè)await會(huì)報(bào)錯(cuò):

于是,我們要為這個(gè)給data賦值的語(yǔ)句加一個(gè)async函數(shù)的包裝:

String data;
setData() async {
  data = await getData();    //getData()延遲執(zhí)行后賦值給data
}
上面這種方法一般用于調(diào)用封裝好的異步接口,比如getData()被封裝到了其他dart文件,通過(guò)使用async函數(shù)對(duì)其調(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請(qǐng)求的數(shù)據(jù)了。就這樣就完了?是滴,只要記住兩點(diǎn):

await關(guān)鍵字必須在async函數(shù)內(nèi)部使用

調(diào)用async函數(shù)必須使用await關(guān)鍵字

PS:await關(guān)鍵字真的很形象,等一等的意思,就是說(shuō),既然你運(yùn)行的時(shí)候都要等一等,那我調(diào)用的時(shí)候也等一等吧
Future簡(jiǎn)單科普

前面?zhèn)€講到過(guò),直接return await ...的時(shí)候,實(shí)際上返回的是一個(gè)延遲計(jì)算的Future對(duì)象,這個(gè)Future對(duì)象是Dart內(nèi)置的,有自己的隊(duì)列策略,我們就來(lái)聊聊這個(gè)Future。

先啰嗦一些關(guān)于Dart在線程方面的知識(shí)。

Dart是基于單線程模型的語(yǔ)言。在Dart也有自己的進(jìn)程(或者叫線程)機(jī)制,名叫isolate。APP的啟動(dòng)入口main函數(shù)就是一個(gè)isolate。玩家也可以通過(guò)引入import "dart:isolate"創(chuàng)建自己的isolate,對(duì)多核CPU的特性來(lái)說(shuō),多個(gè)isolate可以顯著提高運(yùn)算效率,當(dāng)然也要適當(dāng)控制isolate的數(shù)量,不應(yīng)濫用,否則走火入魔自廢武功。有一個(gè)很重要的點(diǎn),Dart中isolate之間無(wú)法直接共享內(nèi)存,不同的isolate之間只能通過(guò)isolate API進(jìn)行通信,當(dāng)然本篇的重點(diǎn)在于Future,不展開(kāi)講isolate,心急的小伙伴可以參考官方閱讀理解或者參考大神tain335的人肉翻譯。

Dart線程中有一個(gè)消息循環(huán)機(jī)制(event loop)和兩個(gè)隊(duì)列(event queuemicrotask queue)。

event queue包含所有外來(lái)的事件:I/O,mouse events,drawing events,timers,isolate之間的message等。任意isolate中新增的event(I/O,mouse events,drawing events,timers,isolate的message)都會(huì)放入event queue中排隊(duì)等待執(zhí)行,好比機(jī)場(chǎng)的公共排隊(duì)大廳。

microtask queue只在當(dāng)前isolate的任務(wù)隊(duì)列中排隊(duì),優(yōu)先級(jí)高于event queue,好比機(jī)場(chǎng)里的某個(gè)VIP候機(jī)室,總是VIP用戶先登機(jī)了,才開(kāi)放公共排隊(duì)入口。

如果在event中插入microtask,當(dāng)前event執(zhí)行完畢即可插隊(duì)執(zhí)行microtask。如果沒(méi)有microtask,就沒(méi)辦法插隊(duì)了,也就是說(shuō),microtask queue的存在為Dart提供了給任務(wù)隊(duì)列插隊(duì)的解決方案。

當(dāng)main方法執(zhí)行完畢退出后,event loop就會(huì)以FIFO(先進(jìn)先出)的順序執(zhí)行microtask,當(dāng)所有microtask執(zhí)行完后它會(huì)從event queue中取事件并執(zhí)行。如此反復(fù),直到兩個(gè)隊(duì)列都為空,如下流程圖:

注意:當(dāng)事件循環(huán)正在處理microtask的時(shí)候,event queue會(huì)被堵塞。這時(shí)候app就無(wú)法進(jìn)行UI繪制,響應(yīng)鼠標(biāo)事件和I/O等事件。胡亂插隊(duì)也是有代價(jià)的~

雖然你可以預(yù)測(cè)任務(wù)執(zhí)行的順序,但你無(wú)法準(zhǔn)確的預(yù)測(cè)到事件循環(huán)何時(shí)會(huì)處理你期望的任務(wù)。例如當(dāng)你創(chuàng)建一個(gè)延時(shí)1s的任務(wù),但在排在你之前的任務(wù)結(jié)束前事件循環(huán)是不會(huì)處理這個(gè)延時(shí)任務(wù)的,也就是或任務(wù)執(zhí)行可能是大于1s的。

OK,了解以上信息之后,再來(lái)回到Future,小伙伴可能已經(jīng)被繞暈了。

Future就是event,很多Flutter內(nèi)置的組件比如前幾篇用到的Http(http請(qǐng)求控件)的get函數(shù)、RefreshIndicator(下拉手勢(shì)刷新控件)的onRefresh函數(shù)都是event。每一個(gè)被await標(biāo)記的句柄也是一個(gè)event,每創(chuàng)建一個(gè)Future就會(huì)把這個(gè)Future扔進(jìn)event queue中排隊(duì)等候安檢~

什么?那microtask呢?當(dāng)然不會(huì)忘了這個(gè),scheduleMicrotask,用法和Future基本一樣。

為什么要用Future?

前面講到,用asyncawait組合,即可向event queue中插入event實(shí)現(xiàn)異步操作,好像Future的存在有些多余的感覺(jué),剛開(kāi)始我本人也有這樣的疑惑,且往下看。

當(dāng)定義Flutter函數(shù)時(shí),還可以指定其運(yùn)行結(jié)果返回值的類(lèi)型,以提高代碼的可讀性:

//定義了返回結(jié)果值為String類(lèi)型
Future getDatas(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");    //因?yàn)轭?lèi)型不匹配,IDE會(huì)報(bào)錯(cuò)
}

Future最主要的功能就是提供了鏈?zhǔn)秸{(diào)用。熟悉ES6語(yǔ)法的小伙伴樂(lè)開(kāi)了花,鏈?zhǔn)秸{(diào)用解決兩大問(wèn)題:明確代碼執(zhí)行的依賴(lài)關(guān)系和實(shí)現(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耦合,將來(lái)如果funA廢掉或者改動(dòng),funB中還需要經(jīng)過(guò)修改以適配變更。

//案例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();
}
//沒(méi)有明確體現(xiàn)出設(shè)置變量和使用變量之間的依賴(lài)關(guān)系,其他開(kāi)發(fā)者難以理解你的代碼邏輯,代碼維護(hù)困難
//并且如果為了防止funA()或者funB()因發(fā)生異常導(dǎo)致程序崩潰
//要到funA()或者funB()中分別加入`try`、`catch`、`finally`

為了解決上面的問(wèn)題,Future提供了一套非常簡(jiǎn)潔的解決方案:

//案例3
 funA(){
  ...set an important variable...    //設(shè)置變量
}

funB(){
  ...use the important variable...   //使用變量
}
main(){
  new Future.then(funA()).then(funB());   // 明確表現(xiàn)出了后者依賴(lài)前者設(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的玩法是asyncawait無(wú)法企及的,因此掌握Future還是很有必要滴。當(dāng)然了,Future的玩法不僅僅局限于案例3,還有很多有趣的玩法,包括和microtask對(duì)象scheduleMicrotask配合使用,我這里就不一一介紹了,大家參考大神tain335的人肉翻譯或者官網(wǎng)閱讀理解吧。

總結(jié)

Dart的isolate中加入了event queuemicrotask queue后,有了一點(diǎn)協(xié)程的感覺(jué),或許這就是Flutter為啥在性能上敢和原生開(kāi)發(fā)叫板的原因之一吧。本篇的內(nèi)容比較抽象,如果還是有不明白的小伙伴,歡迎留言提問(wèn),我盡量回答,哈哈哈,就醬,歡迎加入到Flutter圈子或flutter 中文社區(qū)(官方QQ群:338252156),群里有前后端及全棧各路大神鎮(zhèn)場(chǎng)子,加入進(jìn)來(lái)沒(méi)事就寫(xiě)寫(xiě)APP掙點(diǎn)外快(這個(gè)真的有),順便翻譯翻譯官方英文原稿拉一票粉絲,一舉多得何樂(lè)而不為呢。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/94250.html

相關(guān)文章

  • Flutter 面試知識(shí)點(diǎn)集錦

    摘要:中的的線程是以事件循環(huán)和消息隊(duì)列的形式存在,包含兩個(gè)任務(wù)隊(duì)列,一個(gè)是內(nèi)部隊(duì)列,一個(gè)是外部隊(duì)列,而的優(yōu)先級(jí)又高于。同時(shí)還有處理按住時(shí)的事件額外處理,同時(shí)手勢(shì)處理一般在的子類(lèi)進(jìn)行。谷歌大會(huì)之后,有不少人咨詢了我 Flutter 相關(guān)的問(wèn)題,其中有不少是和面試相關(guān)的,如今一些招聘上也開(kāi)始羅列 Flutter 相關(guān)要求,最后想了想還是寫(xiě)一期總結(jié)吧,也算是 Flutter 的階段復(fù)習(xí)。 ??系統(tǒng)完...

    andong777 評(píng)論0 收藏0
  • flutter實(shí)戰(zhàn)4:新聞列表懶加載下拉手勢(shì)刷新

    摘要:上一篇我們實(shí)現(xiàn)了新聞列表,但在網(wǎng)絡(luò)不好的時(shí)候列表會(huì)白屏,因此為了提高使用體驗(yàn),往列表中加入懶加載效果。其次,引入一個(gè)內(nèi)置的手勢(shì)控件,用于支持下拉刷新列表的效果如下圖將異步執(zhí)行也進(jìn)行了控件化處理,即。 上一篇我們實(shí)現(xiàn)了新聞列表,但在網(wǎng)絡(luò)不好的時(shí)候列表會(huì)白屏,因此為了提高使用體驗(yàn),往列表中加入懶加載效果。其次,引入一個(gè)Flutter內(nèi)置的手勢(shì)控件,用于支持下拉刷新列表的效果如下圖: sho...

    AlienZHOU 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<