Future und async/await
Ein Future<T> steht für ein Ergebnis, das später eintrifft. Mit async und await schreibst du asynchronen Code wie normalen:
Future<String> ladeNutzer(int id) async {
await Future.delayed(Duration(milliseconds: 50));
if (id < 0) throw ArgumentError('ungültige ID');
return 'Nutzer $id';
}
Future<void> main() async {
print(await ladeNutzer(1));
var ergebnisse = await Future.wait([ladeNutzer(2), ladeNutzer(3), ladeNutzer(4)]); // parallel
print(ergebnisse);
try {
await ladeNutzer(-1);
} catch (e) {
print('Fehler: $e');
} finally {
print('fertig');
}
var f = Future.value(42).then((v) => v * 2); // Variante mit then
print(await f);
print(await Future.any([
Future.delayed(Duration(milliseconds: 100), () => 'langsam'),
Future.delayed(Duration(milliseconds: 10), () => 'schnell'),
]));
var mitTimeout = await Future.delayed(Duration(milliseconds: 200), () => 'spät')
.timeout(Duration(milliseconds: 20), onTimeout: () => 'Timeout');
print(mitTimeout);
}Nutzer 1 [Nutzer 2, Nutzer 3, Nutzer 4] Fehler: Invalid argument(s): ungültige ID fertig 84 schnell Timeout
Streams
Ein Stream<T> liefert mehrere Werte über die Zeit (Klicks, Netzwerkdaten, Zeilen einer Datei):
import 'dart:async';
Stream<int> zaehle(int bis) async* { // async* : Stream-Generator
for (var i = 1; i <= bis; i++) {
await Future.delayed(Duration(milliseconds: 10));
yield i;
}
}
Future<void> main() async {
await for (final n in zaehle(3)) {
print('Wert $n');
}
var summe = await zaehle(5).fold<int>(0, (s, x) => s + x);
print('Summe $summe');
print(await zaehle(6).where((x) => x.isEven).map((x) => x * x).toList());
print(await zaehle(10).take(3).toList());
print(await zaehle(4).length);
var controller = StreamController<String>(); // eigener Stream
controller.stream.listen((s) => print('empfangen: $s'), onDone: () => print('Ende'));
controller.add('eins');
controller.add('zwei');
await controller.close();
await Future.delayed(Duration(milliseconds: 10));
var broadcast = Stream.fromIterable([1, 2, 3]).asBroadcastStream();
print(await broadcast.reduce((a, b) => a + b));
}Wert 1 Wert 2 Wert 3 Summe 15 [4, 16, 36] [1, 2, 3] 4 empfangen: eins empfangen: zwei Ende 6
Fehlerbehandlung
class KontoFehler implements Exception {
final String meldung;
KontoFehler(this.meldung);
@override
String toString() => 'KontoFehler: $meldung';
}
double teile(double a, double b) {
if (b == 0) throw KontoFehler('Division durch null');
return a / b;
}
void main() {
try {
print(teile(10, 2));
print(teile(1, 0));
} on KontoFehler catch (e) {
print('Eigener Fehler: $e');
} on FormatException catch (e) {
print('Format: ${e.message}');
} catch (e, stack) {
print('Anderer Fehler: $e ${stack.toString().isNotEmpty}');
} finally {
print('finally');
}
try { int.parse('abc'); } on FormatException catch (e) { print('Format: ${e.message}'); }
try { [1, 2, 3][5]; } on RangeError catch (e) { print('Bereich: ${e.runtimeType}'); }
try { null as int; } catch (e) { print('Typfehler: ${e.runtimeType}'); }
try { throw 'beliebiges Objekt'; } catch (e) { print(e); }
try { try { throw StateError('innen'); } catch (e) { rethrow; } } catch (e) { print('außen: $e'); }
print(int.tryParse('x') ?? -1);
}5.0 Eigener Fehler: KontoFehler: Division durch null finally Format: Invalid radix-10 number Bereich: RangeError Typfehler: _TypeError beliebiges Objekt außen: Bad state: innen -1
Dateien und JSON
import 'dart:convert';
import 'dart:io';
Future<void> main() async {
var dir = await Directory.systemTemp.createTemp('dartdemo');
var datei = File('${dir.path}/demo.txt');
await datei.writeAsString('Zeile 1\nZeile 2\n');
await datei.writeAsString('Zeile 3\n', mode: FileMode.append);
var inhalt = await datei.readAsString();
print(inhalt.length);
var zeilen = await datei.readAsLines();
print(zeilen);
print(await datei.exists());
print(await File('${dir.path}/nicht_da.txt').exists());
var daten = {'name': 'Mia', 'alter': 17, 'tags': ['a', 'b'], 'aktiv': true};
var json = jsonEncode(daten);
print(json);
var zurueck = jsonDecode(json) as Map<String, dynamic>;
print('${zurueck['name']} ${zurueck['tags'][1]} ${zurueck['alter'] + 1}');
print(JsonEncoder.withIndent(' ').convert({'a': 1, 'b': [1, 2]}));
print(utf8.encode('Hä').length);
await dir.delete(recursive: true);
print(await dir.exists());
}24
[Zeile 1, Zeile 2, Zeile 3]
true
false
{"name":"Mia","alter":17,"tags":["a","b"],"aktiv":true}
Mia b 18
{
"a": 1,
"b": [
1,
2
]
}
3
falseMerke
Future<T>,async/await;Future.waitfür Parallelität,.timeoutStream<T>,async*/yield,await for,StreamController- Eigene Exceptions mit
implements Exception;try/on/catch/finally,rethrow dart:io(Dateien),dart:convert(JSON, UTF-8)
Aufgabe
Lade drei simulierte Werte parallel mit Future.wait und summiere sie.