異步編程:futures, async, await

本代碼是學習Futureasync await關鍵字編寫異步代碼。使用嵌入式DartPad編輯器,您能夠經過運行示例代碼並完成練習來測試您的知識。 本文主要包含:數據庫

  • 如何以及什麼時候使用async await關鍵字。

異步代碼的重要性

異步操做使您的程序能夠在等待另外一個操做完成的同時完成工做。如下是一些常見的異步操做:markdown

  • 經過網絡獲取數據。
  • 寫入數據庫。
  • 從文件讀取數據

要在Dart中執行異步操做,可使用Future類和asyncawait關鍵字。網絡

示例:錯誤地使用異步函數

如下示例顯示了使用異步函數(fetchUserOrder())的錯誤方法。稍後,您將使用async和修復示例await。在運行此示例以前,請嘗試找出問題所在–您認爲輸出將是什麼?異步

// This example shows how *not* to write asynchronous Dart code.

String createOrderMessage() {
  var order = fetchUserOrder();
  return 'Your order is: $order';
}

Future<String> fetchUserOrder() =>
    // Imagine that this function is more complex and slow.
    Future.delayed(
      Duration(seconds: 2),
      () => 'Large Latte',
    );

void main() {
  print(createOrderMessage());
  //Your order is: Instance of '_Future<String>'
}

複製代碼

這就是示例沒法打印fetchUserOrder()最終產生的值的緣由:async

  • fetchUserOrder() 是一個異步函數,在延遲後,它提供了一個描述用戶順序的字符串:'Large Latte',
  • 要獲取用戶的訂單,createOrderMessage()應調用fetchUserOrder() 並等待其完成。由於createOrderMessage()它沒有等待fetchUserOrder()到結束,createOrderMessage()沒有獲得字符串值fetchUserOrder(),最終提供的結果。
  • 相反,createOrderMessage()它表明待完成的工做:未完成的future。
  • 因爲createOrderMessage()沒法獲取描述用戶訂單的值,所以該示例沒法在控制檯上打印「 Large Latte」,而是打印「您的訂單是:'_ Future的實例'」。

在接下來的部分中,咱們將瞭解Future以及如何使用Future(使用async和await),以便可以將必要的代碼編寫fetchUserOrder() 爲在控制檯上打印所需的值('Large Latte')。編輯器

關鍵詞:

  • 同步操做:同步操做會阻止其餘操做執行到完成。
  • 同步功能:同步功能僅執行同步操做。
  • 異步操做:異步操做一旦啓動,就能夠在完成以前執行其餘操做。
  • 異步函數:異步函數至少執行一個異步操做,也能夠執行同步操做。

Fulure是什麼?

Fulure表示異步操做的結果,而且能夠具備兩種狀態:未完成或已完成函數

未完成

當您調用異步函數時,它將返回一個未完成的Fulure。Fulure正在等待函數的異步操做完成或引起錯誤。oop

已完成

若是異步操做成功,則Fulure將以一個值完成。不然,它會以錯誤完成。學習

Future值

Future是一個Future<T>因此,咱們能夠將任何值做爲返回類型測試

完成錯誤

若是該函數執行的異步操做因爲任何緣由而失敗,則未來會出現錯誤。

示例:介紹Fulure

Future<void> fetchUserOrder() {
  // Imagine that this function is fetching user info from another service or database.
  return Future.delayed(Duration(seconds: 2), () => print('Large Latte'));
}

void main() {
  fetchUserOrder();
  print('Fetching user order...');
  //Fetching user order... 
  //Large Latte
}

複製代碼

在如下示例中,fetchUserOrder()返回打印到控制檯後完成的Fulure。由於它不返回可用的值,因此 fetchUserOrder()的類型Future<void>。在運行示例以前,請嘗試預測將首先打印的內容:「'Large Latte'」或「Fetching user order...」。

示例:錯誤完成

運行如下示例以查看未來如何完成並出現錯誤。稍後,您將學習如何處理該錯誤。

Future<void> fetchUserOrder() {
// Imagine that this function is fetching user info but encounters a bug
  return Future.delayed(Duration(seconds: 2),
      () => throw Exception('Logout failed: user ID is invalid'));
}

void main() {
  fetchUserOrder();
  print('Fetching user order...');
  
  //Fetching user order...
  //Uncaught Error: Exception: Logout failed: user ID is invalid
}

複製代碼

在此示例中,fetchUserOrder()顯示一個錯誤,指示用戶ID無效。

這個錯誤的演示是爲了理解學習如何使用async和await關鍵字得到結果

快速總結:

  • Future<T> 實例產生類型的值T

  • 若是Future未產生可用價值,則Future的類型爲 Future<void>

  • Future可能處於如下兩種狀態之一:未完成或已完成。

  • 當您調用返回將來的函數時,該函數會將要完成的工做排隊,並返回未完成的將來。

  • 當future的操做完成時,future以一個值或一個錯誤完成。

關鍵詞:

  • Future:Dart Future類。
  • future:Dart Future類的實例。

使用Future:async和await

在async和await關鍵字提供一個聲明的方式來定義異步函數,並使用其結果。使用async和時請記住如下兩個基本準則await:

  • **要定義異步函數,要在函數主體以前添加:async **
  • 該await關鍵字只能在async函數中使用

main()從同步功能轉換爲異步功能的示例。

void main() async { ··· }

複製代碼

若是函數具備聲明的返回類型,則將類型更新爲 Future<T>,其中T是函數返回的值的類型。若是該函數未明確返回值,則返回類型爲 Future<void>

Future<void> main() async { ··· }

如今您有了async函數,可使用await關鍵字等待未來完成:

print(await createOrderMessage());

如如下兩個示例所示,asyncand await關鍵字生成的異步代碼看起來與同步代碼很是類似。異步示例中突出顯示了惟一的區別,

  • 同步
String createOrderMessage() {
  var order = fetchUserOrder();
  return 'Your order is: $order';
}

Future<String> fetchUserOrder() =>
    // Imagine that this function is
    // more complex and slow.
    Future.delayed(
      Duration(seconds: 2),
      () => 'Large Latte',
    );

void main() {
  print('Fetching user order...');
  print(createOrderMessage());
  // Fetching user order...
  // Your order is: Instance of _Future<String>
}

複製代碼
  • 異步
Future<String> createOrderMessage() async {
  var order = await fetchUserOrder();
  return 'Your order is: $order';
  // Fetching user order...
  // Your order is: Large Latte
}

Future<String> fetchUserOrder() =>
    // Imagine that this function is
    // more complex and slow.
    Future.delayed(
      Duration(seconds: 2),
      () => 'Large Latte',
    );

Future<void> main() async {
  print('Fetching user order...');
  print(await createOrderMessage());
}

複製代碼

異步示例在三種方面有所不一樣:

  • 的返回類型createOrderMessage()從變化String到Future<String>
  • 該async關鍵字的函數體以前出現 createOrderMessage()main()
  • 該await關鍵字調用異步函數以前出現 fetchUserOrder()createOrderMessage()

關鍵詞:

  • async:您能夠async在函數主體以前使用關鍵字將其標記爲異步。
  • 異步函數:async函數是帶有async 關鍵字的函數。
  • await:您可使用await關鍵字來獲取異步表達式的完整結果。該await關鍵字只有內工做的async功能。

具備async和await的執行流

一個async函數同步運行直到第一個 await關鍵字。這意味着在async函數體內,第一個await關鍵字以前的全部同步代碼將當即執行。

示例:異步函數中的執行

Future<void> printOrderMessage() async {
  print('Awaiting user order...');
  var order = await fetchUserOrder();
  print('Your order is: $order');
}

Future<String> fetchUserOrder() {
  // Imagine that this function is more complex and slow.
  return Future.delayed(Duration(seconds: 4), () => 'Large Latte');
}

Future<void> main() async {
  countSeconds(4);
  await printOrderMessage();
}

// You can ignore this function - it's here to visualize delay time in this example.
void countSeconds(int s) {
  for (var i = 1; i <= s; i++) {
    Future.delayed(Duration(seconds: i), () => print(i));
  }
}
複製代碼
相關文章
相關標籤/搜索