Future
對象來執行異步操做await
關鍵字來掛起執行知道一個Future操做完成then()
方法catchError()
方法dart是一個單線程的編程語言,若是編寫了任何阻塞執行線程的代碼(例如耗時計算或者I/O),程序就會被阻塞。異步操做可讓你在等待一個操做完成的同時完成其餘工做。Dart使用Future
對象來進行異步操做。html
先來看一個會致使阻塞的程序代碼:web
// Synchronous code
void printDailyNewsDigest() {
var newsDigest = gatherNewsReports(); // Can take a while.
print(newsDigest);
}
main() {
printDailyNewsDigest();
printWinningLotteryNumbers();
printWeatherForecast();
printBaseballScore();
}
複製代碼
程序會收集當天的新聞而且打印出來(耗時操做),而後打印一些用戶感興趣的其餘信息。編程
<gathered news goes here>
Winning lotto numbers: [23, 63, 87, 26, 2]
Tomorrow's forecast: 70F, sunny. Baseball score: Red Sox 10, Yankees 0 複製代碼
這段代碼是有問題的,當printDailyNewsDigest()
方法作耗時操做阻塞,剩下的其餘代碼不管多長時間都只有等到printDailyNewsDigest()
返回結果以後才能繼續執行。api
爲了幫助保持應用程序的響應,Dart庫的做者在定義可能作耗時工做的函數時用了異步模型。這些函數的返回值是一個future。bash
一個future是一個Future的泛型Future<T>
對象,表明了一個異步操做產生的T類型的結果。若是結果的值不可用,future的類型會是Future<void>
,當返回一個future的函數被調用了,將會發生以下兩件事: 1.這個函數加入待完成的隊列而且返回一個未完成的Future
對象。 2.接着,當這個操做結束了,Future
對象返回一個值或者錯誤。異步
編寫返回一個future的代碼時,有兩面兩個可選方法:async
Future
APIasync
和 await
關鍵字是Dart語言異步支持的一部分。容許你不使用Future api像編寫同步代碼同樣編寫異步代碼。一個異步函數的函數體前面要生命async
關鍵字,await
關鍵字僅在異步函數裏生效。編程語言
下面的代碼就是一個使用了Future api的例子。ide
import 'dart:async';
Future<void> printDailyNewsDigest() {
final future = gatherNewsReports();
return future.then(print);
// You don't *have* to return the future here.
// But if you don't, callers can't await it.
}
main() {
printDailyNewsDigest();
printWinningLotteryNumbers();
printWeatherForecast();
printBaseballScore();
}
printWinningLotteryNumbers() {
print('Winning lotto numbers: [23, 63, 87, 26, 2]');
}
printWeatherForecast() {
print("Tomorrow's forecast: 70F, sunny.");
}
printBaseballScore() {
print('Baseball score: Red Sox 10, Yankees 0');
}
const news = '<gathered news goes here>';
const oneSecond = Duration(seconds: 1);
// Imagine that this function is more complex and slow. :)
Future<String> gatherNewsReports() =>
Future.delayed(oneSecond, () => news);
複製代碼
在main()
方法裏面printDailyNewsDigest()
是一個被調用的,可是由於等待了一秒延遲執行,因此在最後才被打印出來。這個程序的執行順序以下:函數
1.程序開始執行
2.main方法調用printDailyNewsDigest()
,可是不會當即返回,會調用gatherNewsReports()
3.gatherNewsReports()
開始收集新聞同時返回一個Future
。
4.printDailyNewsDigest()
使用then()
指定一個Future的響應結果,調用then()
返回一個新完成的Future結果做爲他的回調。
5.剩下的print方法是同步的會依次執行。
6.當全部的新聞都被收集到了,帶有新聞信息的Future被gatherNewsReports()
返回。
7.then()
方法執行,將future返回的String做爲參數傳遞給print
打印。
future.then(print)
等同於future.then((newsDigest) => print(newsDigest))
因此printDailyNewsDigest()
還能夠寫成:
Future<void> printDailyNewsDigest() {
final future = gatherNewsReports();
return future.then((newsDigest) {
print(newsDigest);
// Do something else...
});
}
複製代碼
newsDigest是gatherNewsReports()
返回的結果。
即時這個Future的類型是Future<void>
,也須要傳遞一個參數給then()
的回調,直接用下劃線_
表示。
Future<void> printDailyNewsDigest() {
final future = gatherNewsReports();
return future.then((_) {
// Code that doesn't use the `_` parameter...
print('All reports printed.');
});
}
複製代碼
在Future api裏,能夠使用catchError()
捕獲錯誤:
Future<void> printDailyNewsDigest() =>
gatherNewsReports().then(print).catchError(handleError);
複製代碼
若是請求不到新聞而且失敗了,上面的代碼將會執行:
1.gatherNewsReports()
完成返回的future攜帶了error
2.then()
方法中的print不會被執行
3.catchError()
捕獲處處理錯誤,future被catchError()
正常完成並返回,錯誤不會繼續傳遞下去。
更多細節閱讀 Futures and Error Handling
有三個函數,expensiveA()
、 expensiveB()
和 expensiveC()
, 它們都返回Future對象。你能夠順序調用它們(one by one),或者也能夠同時調用三個函數而且當全部結果都返回時再作處理。Future api支持以上的操做。
按順序使用then()調用每一個方法
expensiveA()
.then((aValue) => expensiveB())
.then((bValue) => expensiveC())
.then((cValue) => doSomethingWith(cValue));
複製代碼
這是個嵌套調用,上一個函數的返回結果做爲下一個函數的參數。
若是好幾個函數的執行順序可有可無,能夠使用Future.wait()
。
Future.wait([expensiveA(), expensiveB(), expensiveC()])
.then((List responses) => chooseBestResponse(responses, moreInfo))
.catchError(handleError);
複製代碼
當傳遞一個future列表給Future.wait()
時,它會當即返回一個Future,可是直到列表裏的future都完成的時候,這個Future纔會完成,他會返回一個列表裏面是每個future產生的結果數據。
若是任何一個調用的函數產生了錯誤,都會被catchError()
捕獲到去處理錯誤。