EMZETT.
Login

Kurz: Ein Future<T> steht für ein Ergebnis, das später eintrifft. Mit async und await schreibst du asynchronen Code wie normalen:

Teil des Kurses Dart

Kapitel 5 von 8 im Kurs Dart. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

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

Ausgabe:

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

Ausgabe:

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

Ausgabe:

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

Ausgabe:

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
false

Merke

  • Future<T>, async/await; Future.wait für Parallelität, .timeout
  • Stream<T>, async*/yield, await for, StreamController
  • Eigene Exceptions mit implements Exception; try/on/catch/finally, rethrow
  • dart:io (Dateien), dart:convert (JSON, UTF-8)

Übungsaufgabe

Lade drei simulierte Werte parallel mit Future.wait und summiere sie.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Klassen, Vererbung und Mixins

Weiter: Flutter und das Dart-Ökosystem

Alle Kapitel: Dart im Überblick