Futures & async/await
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 76 von 110.
In realen Anwendungen nehmen viele Operationen Zeit in Anspruch – das Abrufen von Daten von einem Server, das Lesen von Dateien oder das Warten auf Benutzereingaben. Dart bewältigt diese mit Future, was einen Wert darstellt, der irgendwann in der Zukunft verfügbar sein wird.
Ein Future ist wie ein Versprechen: „Ich werde dir das Ergebnis geben, wenn es fertig ist.“ Du kannst eines mit Future.delayed() erstellen, um eine Operation zu simulieren, die Zeit in Anspruch nimmt:
Future<String> fetchUserName() {
return Future.delayed(
Duration(seconds: 1),
() => 'Alice',
);
}Um mit dem Ergebnis eines Future zu arbeiten, verwenden Sie async und await. Markieren Sie Ihre Funktion als async und verwenden Sie dann await, um die Ausführung zu pausieren, bis das Future abgeschlossen ist:
Future<void> main() async {
print('Fetching user...');
String name = await fetchUserName();
print('Hello, $name!');
}
Future<String> fetchUserName() {
return Future.delayed(
Duration(seconds: 1),
() => 'Alice',
);
}Ohne await würden Sie ein Future<String> anstelle des tatsächlichen Strings erhalten. Das await-Schlüsselwort entpackt das Future und gibt Ihnen den darin enthaltenen Wert. Beachten Sie, dass jede Funktion, die await verwendet, als async markiert sein muss und automatisch ein Future zurückgibt.
Du kannst Werte auch direkt aus async-Funktionen zurückgeben – Dart verpackt sie automatisch in ein Future:
Future<int> calculateTotal() async {
var a = await fetchNumber();
var b = await fetchNumber();
return a + b; // Automatisch in Future<int> verpackt
}Aufgabe
EinfachLass uns einen Wetterdienst bauen, der das Abrufen von Wetterdaten aus verschiedenen Städten simuliert! Du wirst üben, Future, async und await zu verwenden, um Operationen zu handhaben, die Zeit in Anspruch nehmen.
Du wirst deinen Code in zwei Dateien organisieren:
weather_service.dart: Erstelle eineWeatherService-Klasse, die das Abrufen von Wetterinformationen simuliert. Deine Klasse sollte Folgendes haben:- Eine Methode
fetchTemperature(String city), die einFuture<int>zurückgibt. VerwendeFuture.delayed()mit einer Dauer von 100 Millisekunden, um eine Netzwerkverzögerung zu simulieren. Die Methode sollte eine Temperatur basierend auf dem Stadtnamen zurückgeben: Gib die Länge des Stadtnamens multipliziert mit 3 zurück. - Eine Methode
fetchCondition(String city), die einFuture<String>zurückgibt. VerwendeFuture.delayed()mit 100 Millisekunden Verzögerung. Gib'Sunny'zurück, wenn der Stadtname eine gerade Anzahl von Zeichen hat, andernfalls gib'Cloudy'zurück. - Eine asynchrone Methode
getFullReport(String city), die einFuture<String>zurückgibt. Diese Methode sollte sowohl auffetchTemperatureals auch auffetchConditionwarten (await) und dann einen formatierten String zurückgeben:'[city]: [temperature]C, [condition]'
- Eine Methode
main.dart: Importiere deinen Wetterdienst und demonstriere, wie asynchrone Operationen funktionieren. Deine main-Funktion sollte asynchron sein und:- Erstelle eine
WeatherService-Instanz - Gib
Fetching weather data...aus - Warte auf den vollständigen Bericht für
'Paris'und gib ihn aus - Warte auf den vollständigen Bericht für
'Tokyo'und gib ihn aus - Warte auf den vollständigen Bericht für
'London'und gib ihn aus - Gib
Done!aus
- Erstelle eine
Beachte, wie jeder Aufruf von getFullReport darauf wartet, dass sowohl die Temperatur als auch der Zustand abgerufen werden, bevor das kombinierte Ergebnis zurückgegeben wird. Das Schlüsselwort await pausiert die Ausführung, bis jedes Future abgeschlossen ist!
Erwartete Ausgabe:
Fetching weather data...
Paris: 15C, Cloudy
Tokyo: 15C, Cloudy
London: 18C, Sunny
Done!Spickzettel
Ein Future repräsentiert einen Wert, der in der Zukunft verfügbar sein wird. Es wird für Operationen verwendet, die Zeit in Anspruch nehmen, wie das Abrufen von Daten oder das Lesen von Dateien.
Erstellen Sie ein Future mit Future.delayed():
Future<String> fetchUserName() {
return Future.delayed(
Duration(seconds: 1),
() => 'Alice',
);
}Verwenden Sie async und await, um mit Futures zu arbeiten. Markieren Sie die Funktion als async und verwenden Sie await, um die Ausführung zu pausieren, bis das Future abgeschlossen ist:
Future<void> main() async {
print('Fetching user...');
String name = await fetchUserName();
print('Hello, $name!');
}Das Schlüsselwort await entpackt das Future und liefert Ihnen den tatsächlichen Wert. Ohne es würden Sie ein Future<String> anstelle des Strings erhalten.
Jede Funktion, die await verwendet, muss als async markiert sein und gibt automatisch ein Future zurück.
Rückgabewerte von async-Funktionen werden automatisch in ein Future verpackt:
Future<int> calculateTotal() async {
var a = await fetchNumber();
var b = await fetchNumber();
return a + b; // Automatically wrapped in Future<int>
}Probier es selbst
import 'weather_service.dart';
Future<void> main() async {
// TODO: Erstelle eine WeatherService-Instanz
// TODO: Gib 'Fetching weather data...' aus
// TODO: Erwarte und gib den vollständigen Bericht für 'Paris' aus
// TODO: Erwarte und gib den vollständigen Bericht für 'Tokyo' aus
// TODO: Erwarte und gib den vollständigen Bericht für 'London' aus
// TODO: Gib 'Done!' aus
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienBibliotheken & ImportsEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenInstanzvariablenKonstruktor-GrundlagenWiederholung – Einfacher Taschenrechner4Null-Sicherheit
Einführung in Null-SicherheitNullable vs. Non-NullableDie ? und ! OperatorenLate-Schlüsselwort & Null-SicherheitNull-aware OperatorenNull-Sicherheit in KlassenZusammenfassung – Benutzerprofil-System7Abstrakte Klassen & Interfaces
Abstrakte KlassenAbstrakte MethodenInterfaces in DartImplizite InterfacesImplementieren vs. ErweiternMehrfache InterfacesRückblick – Shape Calculator10Collections & Generics
Überblick über List, Set und MapTypsichere CollectionsGenerische KlassenGenerische MethodenGenerische ConstraintsIterable & IteratorZusammenfassung – Generische Speicherung13Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums mit Methoden16Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen2Konstruktoren in Dart
Standard-KonstruktorBenannte KonstruktorenInitialisierungslistenKonstante KonstruktorenFactory-KonstruktorenWeiterleitende KonstruktorenZusammenfassung – Shape Builder5Kapselung
Öffentliche vs. private MemberDie _ Präfix-KonventionSichtbarkeit auf Library-EbeneGetter & Setter im DetailInformation HidingRückblick – Schülerdatensätze8Mixins
Einführung in MixinsMixins erstellenMehrere Mixins verwendenDas on-Schlüsselwort in MixinsMixin vs. VererbungMixin vs. InterfaceZusammenfassung - Tiersystem11Spezielle Methoden
toString() überschreibenhashCode & == überschreibenComparable-Interfacecall()-MethodenoSuchMethod überschreibenZusammenfassung – Eigene Collection14Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster3Klasseneigenschaften
Instanz- vs. statische MemberFinal & Const FelderLate-VariablenStatische Methoden & FelderGetter und SetterZusammenfassung – Bankkonto-Manager6Vererbung
Grundlagen der VererbungDas super-SchlüsselwortMethoden überschreibenDie @override-AnnotationDas final-Klassen-SchlüsselwortKonstruktoren & VererbungRückblick – Mitarbeiter-Hierarchie9Polymorphismus
Polymorphismus-GrundlagenPolymorphismus über InterfacesTypprüfung zur LaufzeitDie is & as OperatorenDas covariant SchlüsselwortZusammenfassung – Payment Processor12Asynchrone OOP
Futures & async/awaitStreams GrundlagenStream ControllerAsynchrone KonstruktorenAsync in KlassenmethodenZusammenfassung – Data Fetcher