當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Dart Future用法及代碼示例


dart:async 庫中Future 類的用法介紹如下。

異步計算的結果。

asynchronous computation 在啟動時不能立即提供結果,這與同步計算不同,同步計算通過返回值或拋出來立即計算結果。異步計算可能需要等待程序外部的某些事情(讀取文件、查詢數據庫、獲取網頁),這需要時間。在結果可用之前,異步計算不會阻塞所有計算,而是立即返回一個Future,它將與結果一起eventually"complete"。

異步編程

要執行異步計算,請使用 async 函數,該函數始終會產生未來。在這樣的異步函數中,您可以使用await 操作來延遲執行,直到另一個異步計算有結果。在等待函數的執行被延遲的同時,程序並沒有被阻塞,可以繼續做其他事情。

例子:

import "dart:io";
Future<bool> fileContains(String path, String needle) async {
   var haystack = await File(path).readAsString();
   return haystack.contains(needle);
}

這裏來自 dart:ioFile.readAsString 方法是一個返回 Future<String> 的異步函數。 fileContains 函數在其主體之前標有async,這意味著您可以在其中使用await,並且它必須返回一個未來。對File(path).readAsString() 的調用啟動將文件讀入字符串並生成最終包含結果的Future<String>。然後 await 等待該未來以字符串完成(或錯誤,如果讀取文件失敗)。在等待期間,程序可以做其他事情。當 future 以字符串結束時,fileContains 函數計算一個布爾值並返回它,然後完成它在第一次調用時返回的原始未來。

如果未來以 error 完成,則等待該未來將(重新)拋出該錯誤。在這裏的示例中,我們可以添加錯誤檢查:

import "dart:io";
Future<bool> fileContains(String path, String needle) async {
  try {
    var haystack = await File(path).readAsString();
    return haystack.contains(needle);
  } on FileSystemException catch (exception, stack) {
    _myLog.logError(exception, stack);
    return false;
  }
}

您使用普通的 try /catch 來捕獲等待的異步計算的失敗。

一般來說,在編寫異步代碼時,你應該總是等待一個未來的產生,而不是等到另一個異步延遲之後。這可確保您準備好接收未來可能產生的任何錯誤,這一點很重要,因為 no-one 正在等待的異步錯誤是 uncaught 錯誤,並且可能會終止正在運行的程序。

使用Future API 進行編程。

Future 類還提供了更直接的低級函數來訪問它完成的結果。 asyncawait 語言特性建立在此函數之上,有時直接使用它是有意義的。有些事情你不能通過一次await ing 一個未來來完成。

使用 Future ,您可以手動注冊處理值或錯誤的回調(一旦可用)。例如:

Future<int> future = getFuture();
future.then((value) => handleValue(value))
      .catchError((error) => handleError(error));

由於 Future 可以通過兩種方式完成,使用值(如果異步計算成功)或錯誤(如果計算失敗),您可以為其中一種或兩種情況安裝回調。

在某些情況下,我們說未來已完成 with another future 。這是一種簡短的方式來說明未來以相同的方式完成,具有相同的值或錯誤,一旦另一個未來本身完成,另一個未來。完成未來的平台庫中的大多數函數(例如 Completer.completeFuture.value )也接受另一個未來,並自動處理將結果轉發到正在完成的未來。

注冊回調的結果本身就是一個 Future ,它反過來通過使用原始未來結果調用相應回調的結果來完成。如果調用的回調拋出,則新的未來完成並出現錯誤。例如:

Future<int> successor = future.then((int value) {
    // Invoked when the future is completed with a value.
    return 42;  // The successor is completed with the value 42.
  },
  onError: (e) {
    // Invoked when the future is completed with an error.
    if (canHandle(e)) {
      return 499;  // The successor is completed with the value 499.
    } else {
      throw e;  // The successor is completed with the error e.
    }
  });

如果未來在完成錯誤時沒有任何注冊的處理程序,它會將錯誤轉發到“uncaught-error 處理程序”。此行為可確保不會以靜默方式丟棄任何錯誤。但是,這也意味著應該盡早安裝錯誤處理程序,以便它們在未來完成時出現錯誤。以下示例演示了這個潛在的錯誤:

var future = getFuture();
Timer(const Duration(milliseconds: 5), () {
  // The error-handler is not attached until 5 ms after the future has
  // been received. If the future fails before that, the error is
  // forwarded to the global error-handler, even though there is code
  // (just below) to eventually handle the error.
  future.then((value) { useValue(value); },
              onError: (e) { handleError(e); });
});

注冊回調時,分別注冊兩個回調通常更具可讀性,首先使用帶有一個參數(值處理程序)的then,然後使用第二個catchError 來處理錯誤。它們中的每一個都會將它們不處理的結果轉發給它們的後繼者,它們一起處理值和錯誤結果。它還具有 catchError 處理 then 值回調中的錯誤的額外好處。使用順序處理程序而不是並行處理程序通常會導致代碼更容易推理。它還使異步代碼與同步代碼非常相似:

// Synchronous code.
try {
  int value = foo();
  return bar(value);
} catch (e) {
  return 499;
}

基於期貨的等效異步代碼:

Future<int> asyncValue = Future(foo);  // Result of foo() as a future.
asyncValue.then((int value) {
  return bar(value);
}).catchError((e) {
  return 499;
});

與同步代碼類似,錯誤處理程序(使用 catchError 注冊)正在處理由 foobar 引發的任何錯誤。如果 error-handler 已注冊為 then 調用的 onError 參數,則它不會捕獲來自 bar 調用的錯誤。

期貨可以注冊多個callback-pair。每個後繼者都被獨立對待,並被視為唯一的後繼者。

未來也可能永遠無法完成。在這種情況下,不會調用回調。如果可能的話,通常應該避免這種情況,除非它有非常清楚的記錄。

可用的擴展

FutureExtensions

相關用法


注:本文由純淨天空篩選整理自dart.dev大神的英文原創作品 Future<T> class。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。