dart:async stellt die zentralen Fähigkeiten für die asynchrone Programmierung in Dart bereit: Future, Stream.
- Für die Nutzung von
Future / Streammuss dart:async nicht zwingend manuell importiert werden, da dart:core diese Typen bereits exportiert;- Sollen Typen wie
StreamController,StreamSubscription,ParallelWaitErrorverwendet werden, ist ein expliziter Import erforderlich:
import 'dart:async';Code-Sprache: JavaScript (javascript)
Zwei Kernkonzepte:
- Future: Steht für ein einmaliges asynchrones Ergebnis (es wird zu einem späteren Zeitpunkt genau ein Wert oder ein Fehler erzeugt)
- Stream: Steht für eine fortlaufende Reihe asynchroner Daten (es entstehen nacheinander mehrere Werte, vergleichbar mit einem Ereignisstrom)
Future
1. async / await
Die bevorzugte Schreibweise mit besserer Lesbarkeit als verkettete .then()-Aufrufe
- Funktionen mit dem Schlüsselwort
asyncgeben immer ein Future zurück; awaitwartet auf den Abschluss eines Futures und hält die Ausführung des aktuellen Codes bis zur Ergebnisrückgabe an;- Mit
try-catchlassen sich asynchrone Ausnahmen abfangen.
// async 函数返回 Future
Future<String> findEntryPoint() async => "main.dart";
Future<int> runExecutable(String entry, List args) async => 0;
Future<void> flushThenExit(int code) async {}
// await 写法(推荐)
Future<void> runUsingAsyncAwait() async {
try {
var entryPoint = await findEntryPoint();
var exitCode = await runExecutable(entryPoint, []);
await flushThenExit(exitCode);
} catch (e) {
// 统一捕获异常
print("出错:$e");
}
}
2. .then() / .catchError() traditionelle verkettete Syntax
.then(): Führt einen Callback aus, wenn das Future erfolgreich abgeschlossen wird. Es gibt ein neues Future zurück, sodass die Kette weitergeführt werden kann.catchError(): Fängt Fehler ab; muss an den Rückgabewert von then angehängt werden, sonst werden Fehler innerhalb des then-Blocks nicht erkannt
void runUsingFuture() {
findEntryPoint()
.then((entryPoint) {
return runExecutable(entryPoint, []);
})
.then(flushThenExit)
.catchError((e) {
print("异常:$e");
});
}
3. Auf mehrere parallele Futures warten
① Future.wait()
Wartet bis alle Aufgaben beendet sind; schlägt der gesamte Vorgang fehl, sobald nur ein Future einen Fehler liefert
Future<void> task1() async {}
Future<void> task2() async {}
Future<void> task3() async {}
void testWait() async {
await Future.wait([
task1(),
task2(),
task3(),
]);
print("全部任务执行完成");
}
② List.wait / Record.wait (neues Feature, differenzierte Fehlerbehandlung bei parallelen Vorgängen)
Löst eine ParallelWaitError aus. Dadurch lässt sich feststellen, welche Vorgänge erfolgreich und welche fehlgeschlagen sind – ohne gegenseitige Unterbrechung.
Future<int> delete() async => 1;
Future<String> copy() async => "ok";
Future<bool> errorTask() async {
throw Exception("任务失败");
}
void main() async {
try {
// 列表形式
var results = await [delete(), copy(), errorTask()].wait;
} on ParallelWaitError<List<Object?>, List<AsyncError?>> catch (e) {
print(e.values); // 成功有值,失败为null
print(e.errors); // 成功为null,失败存放错误信息
}
// Record元组形式:支持不同类型Future
try {
final (resInt, resStr, resBool) = await (delete(), copy(), errorTask()).wait;
} on ParallelWaitError<(int?, String?, bool?), (AsyncError?, AsyncError?, AsyncError?)> catch(e) {
}
}
Stream
Ein Stream steht für eine fortlaufende Folge asynchroner Daten (zeilenweises Einlesen von Dateien, Schaltflächenklick-Ereignisse, Netzwerkdatenströme).
Zwei Verwendungsarten
1:await for asynchrone for-Schleife (übersichtlich, ähnlich der synchronen Iteration)
Geeignet für endliche Datenströme; nicht für unendliche Ereignisströme (z. B. Oberflächenklicks), da nachfolgender Code blockiert wird.
import 'dart:io';
Future<void> readFileByAwaitFor() async {
var file = File("config.txt");
Stream<List<int>> input = file.openRead();
var lines = input
.transform(utf8.decoder)
.transform(const LineSplitter());
try {
await for (final line in lines) {
print("读取一行:$line");
}
print("文件读取完毕");
} catch (e) {
print("读取异常 $e");
}
}
2 .listen() Abonnement zum Lauschen (für unendliche Ereignisströme geeignet)
inputStream.listen(
(data) {
// 收到数据回调
},
onError: (err) {
// 发生错误
},
onDone: () {
// 流正常关闭完成
},
);
listen gibt ein
StreamSubscriptionzurück. Darauf kann.cancel()aufgerufen werden, um das Abonnement zu beenden.
Häufig genutzte Stream-Methoden
- Filtern:
where() - Begrenzen:
take()、takeWhile() - Elemente überspringen:
skip()、skipWhile() - Einzelnes Element abrufen:
first、last、single、firstWhere()
Datenumwandlung bei Streams mit transform()
Ändert den Datentyp des Stroms mithilfe eines Transformators (typischer Anwendungsfall: Binärstrom zu Zeichenkette umwandeln)
var lines = inputStream
.transform(utf8.decoder) // List<int> → String
.transform(const LineSplitter()); // String → 逐行字符串
Auswahlhilfe: listen() vs await for
- Dateilesen, endliche Sequenzdaten →
await for - UI-Ereignisse, dauernde Nachrichtenübermittlung und weitere unendliche Ströme →
.listen() - Sobald await for startet, wartet es bis zum Ende des Stroms. Bei unendlichen Ereignisströmen bleibt das Programm hängen
Bibliothek dart:async