Flutter 的異步機制Future

Dart是一個單線程語言,能夠理解成物理線路中的串聯,當其遇到有延遲的運算(好比IO操做、延時執行)時,線程中按順序執行的運算就會阻塞,用戶就會感受到卡頓,因而一般用異步處理來解決這個問題。編程

Dart異步編程有兩種方式:Future和Streamjson

Future至關於40米大砍刀,Stream至關於一捆40米大砍刀。dart提供了關鍵字async(異步)和await(延遲執行),至關於普通的便捷的小匕首,而小匕首是咱們平時常常用到的。api

當遇到有須要延遲的運算(async)時,將其放入到延遲運算的隊列(await)中去,把不須要延遲運算的部分先執行掉,最後再來處理延遲運算的部分。app

async和await

async await 這兩個關鍵字是dart語言的特性,能讓你寫出看起來像是「同步」的「異步」代碼,先看一個方法案例:異步

/*HTTP的get請求返回值爲Future<String>類型,即其返回值將來是一個String類型的值*/
  /*async關鍵字聲明該函數內部有代碼須要延遲執行*/ getData() async { /*await關鍵字聲明運算爲延遲執行,而後return運算結果*/
    return await http.get(Uri.encodeFull(url), headers: {"Accept": "application/json"}); }

而後咱們嘗試調用這個方法,並獲取返回值。async

String data = getDate();

而後控制檯報錯了….ide

爲何呢?由於data是String類型,而函數getData()是一個異步操做函數,其返回值是一個await延遲執行的結果。在Dart中,有await標記的運算,其結果值都是一個Future對象,Future不是String類型,因此就報錯了。異步編程

總結一下:函數

在請求方法中直接 return await .. .的時候,實際上返回的是一個延遲計算的Future對象。url

還有兩點須要注意:

  • await關鍵字必須在async函數內部使用
  • 調用async函數必須使用await關鍵字

就是說:

1.要想 return await … ,那麼方法首先是 async 的,如上方方法。

2.使用 async 標註的方法,必需要用 await 接收返回值,好比上方方法在接收返回值時,須要加入 await 

var data = await getData();

什麼是Future

Future表示一件「未來」會發生的事情,未來能夠從Future中取到一個值。當一個方法返回一個Future的事情,發生兩件事情:

  • 這個方法將某件事情排隊,返回一個未完成的Future
  • 當這件事情完畢以後,Future的狀態會變成已完成,這個時候就能夠取到這件事情的返回值了。

要取到這個「返回值」,有兩種方式:

  • 使用async配合await
  • 使用Future提供的api

咱們看這兩種實現方式的案例:

一、使用async配合await

先看個案例,等待3秒後返回‘我是用戶’:

/*模擬異步加載用戶信息*/ Future _getUserInfo() async{ await new Future.delayed(new Duration(milliseconds: 3000)); return "我是用戶"; } /*加載用戶信息,順便打印時間看看順序*/ Future _loadUserInfo() async{ print("_loadUserInfo:${new DateTime.now()}"); print(await _getUserInfo()); print("_loadUserInfo:${new DateTime.now()}"); }

咱們在initState中調用該方法:

@override void initState(){ print("initState:${new DateTime.now()}"); _loadUserInfo(); print("initState:${new DateTime.now()}"); super.initState(); }

打印結果以下:

I/flutter ( 1802): initState:2019-06-20 09:46:40.097339 I/flutter ( 1802): _loadUserInfo:2019-06-20 09:46:40.103542 I/flutter ( 1802): Instance of 'Future<dynamic>' I/flutter ( 1802): initState:2019-06-20 09:46:40.108510 I/flutter ( 1802): 我是用戶 I/flutter ( 1802): _loadUserInfo:2019-06-20 09:46:43.117136

what?

很明顯,打印結果並無按照串聯的方式依次打印。

flutter中會改造帶asyc關鍵字的方法,讓這個方法脫離主流程,變成「後面一點」執行(經過scheduleMicrotask),因此可讓咱們的程序「看起來」是順序執行的。

二、Future api

咱們修改一下 loadUserInfo() 方法:

/*加載用戶信息,順便打印時間看看順序*/ Future _loadUserInfo() async{ print("_loadUserInfo:${new DateTime.now()}"); _getUserInfo().then((info){ print(info); }); print("_loadUserInfo:${new DateTime.now()}"); }

再次運行輸出一下:

I/flutter ( 1802): initState:2019-06-20 09:50:32.488765 I/flutter ( 1802): _loadUserInfo:2019-06-20 09:50:32.494751 I/flutter ( 1802): _loadUserInfo:2019-06-20 09:50:32.499725 I/flutter ( 1802): Instance of 'Future<dynamic>' I/flutter ( 1802): initState:2019-06-20 09:50:32.499970 I/flutter ( 1802): 我是用戶

兩次輸出是有不一樣的,主要不一樣在於第二個 loadUserInfo 的日誌打印,與‘我是用戶’的輸出順序,爲何有差別?

await會阻塞流程,等待緊跟着的的Future執行完畢以後,再執行下一條語句,而若是用了Future.then這個api,那麼就不會等待,直接執行下面的語句,等Future執行完了,再調用then這個方法。

總結

在請求方法中直接 return await .. .的時候,實際上返回的是一個延遲計算的Future對象。

有兩點須要注意:

  • await關鍵字必須在async函數內部使用
  • 調用async函數必須使用await關鍵字

Flutter 中有兩種實現異步編程的方式:Future api、 async await

平常開發中經常使用的是 async await Future 搭配。

相關文章
相關標籤/搜索