2、Dart:非同步程式設計之Futures;

Melrose發表於2019-04-13

  Dart程式碼在一個執行的'執行緒'中執行。Future物件代表非同步操作的結果:稍後要完成的處理或I/O。要暫停執行直到將來完成,要在非同步函式中使用await(或使用then())。要捕獲錯誤,要在非同步函式中使用try-catch表示式(或使用catchError())。要同時執行程式碼,請建立isolate

Futures

  future是Future<T>物件,表示產生型別T結果的非同步操作。如果沒有返回結果,則future的型別為Future <void>,當呼叫返回future的函式時,會發生兩件事:

  1. 該函式將要完成的工作排隊並返回未完成的Future物件。
  2. 稍後,當操作完成時,Future物件將以值或錯誤完成。

  編寫依賴於未來的程式碼時,您有兩種選擇:

  • 使用asyncawait
  • 使用Futureapi。

async和await

  asyncawait關鍵字是Dart語言非同步支援的一部分。 它們允許編寫看起來像同步程式碼的非同步程式碼,而不使用Future API。 非同步函式是在其正文之前具有async關鍵字的函式。 await關鍵字僅適用於非同步函式。

注意:在Dart 1.x中,非同步函式立即暫停執行。 在Dart 2中,非同步函式不是立即掛起,而是同步執行,直到第一個等待或返回。

import 'dart:async';

Future<void> printDailyNewsDigest() async {
  var newsDigest = await gatherNewsReports();
  print(newsDigest);
}
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);

Future<String> gatherNewsReports() =>
    Future.delayed(oneSecond, () => news);
複製程式碼
處理錯誤

  如果Future-returns函式因錯誤而完成,您可能希望捕獲該錯誤。 非同步函式可以使用try-catch處理錯誤:

Future<void> printDailyNewsDigest() async {
  try {
    var newsDigest = await gatherNewsReports();
    print(newsDigest);
  } catch (e) {
    // Handle error...
  }
}
複製程式碼
順序處理

  可以使用多個await表示式來確保每個語句在執行下一個語句之前完成:

main() async {
  await expensiveA();
  await expensiveB();
  doSomethingWith(await expensiveC());
}
複製程式碼

expensiveA()完成之前,expensiveB()函式不會執行,依此類推。

Future API

  在Dart 1.9中新增asyncawait之前,必須使用Future API。 您可能仍會看到舊程式碼中使用的Future API以及需要比async-await提供的功能更多的程式碼。

  要使用Future API編寫非同步程式碼,可以使用then()方法註冊回撥。 當Future完成時,此回撥將觸發。

import 'dart:async';

Future<void> printDailyNewsDigest() {
  final future = gatherNewsReports();
  return future.then(print);
}

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);


Future<String> gatherNewsReports() =>
    Future.delayed(oneSecond, () => news);
複製程式碼

  需要為then()的回撥提供一個引數,即使Future的型別為Future 。 按照慣例,未使用的引數名為_(下劃線)。

final future = printDailyNewsDigest();
return future.then((_) {
  print('All reports printed.');
});
複製程式碼
處理錯誤

  使用Future API,您可以使用catchError()捕獲錯誤:

Future<void> printDailyNewsDigest() =>
    gatherNewsReports().then(print).catchError(handleError);
複製程式碼
使用Future.wait()完成多個Future

  如果函式的執行順序不重要,可以使用Future.wait()。當傳遞Future.wait()一個Futures List時,它會立即返回一個Future。 在所有給定的Futures完成之前,Future不會完成。 然後它以一個List完成,該List包含原始列表中每個future的值。

Future.wait([expensiveA(), expensiveB(), expensiveC()])
    .then((List responses) => chooseBestResponse(responses, moreInfo))
    .catchError(handleError);
複製程式碼

  如果任何呼叫的函式因異常而完成,則Future.wait()返回的Future也會以異常完成。 使用catchError()來處理異常。

相關文章