Asynchron programmieren mit Dart

Dart Stream
Streams in Dart
Vor einer gefühlten Ewigkeit hatte ich in diesem Blog schon über Streams in Dart geschrieben. 
Nun ist das schon eine Weile her und ich denke es kann nicht schaden das Thema noch einmal aufzugreifen.

Bevor wir uns Details anschauen noch einmal eine Auffrischung der Basis !



Synchron versus Asynchron


Wenn wir in Dart ein Programm schreiben, wird es abgearbeitet bis es beendet wird. Das heisst Zeile für Zeile unseres Codes wird ausgeführt, in der von uns bestimmten Reihenfolge. Das Programmende können wir als Programmierer bestimmen, oder der Benutzer beendet das Programm mit Mechanismen die außerhalb des Codes liegen, dem Taskmanager in Windows als Beispiel.
Die nächste Zeile im Code kann jeweils erst dann ausgeführt werden, wenn die aktuelle verarbeitet ist und etwaige Resultate dieser Zeile vorliegen.
Der Vorteil dieser synchronen Abarbeitung des Codes ist, das wir immer mit konkreten Ergebnissen arbeiten. Der Nachteil ist, das unser Programm unter Umständen auf das Ergebnis einer Operation warten muss, da sie mehr Zeit in Anspruch nimmt. Warten auf ein Ergebnis heisst aber auch, das unser Programm blockiert ist, solange dieses nicht vorliegt. 

Die Lösung für diese Problematik ist die asynchrone Programmierung. Sie wartet nicht auf das Ergebnis, sondern stellt sicher das, sobald das Ergebnis da ist, korrekt damit umgegangen wird. Inzwischen aber kann unser Code weiter abgearbeitet werden, ohne blockiert zu sein. Nun gehen wir ins Detail.

Future


Dart stellt uns zur Implementierung von asynchronem Code Hilfsmittel zur Verfügung. Das einte ist die Future Klasse. Der erste große Unterschied zu Stream ist, das ein Future besser für Einzelfälle eingesetzt werden kann. Hier ein Beispiel:

void main(){
   var zukunft = Future.value(14);
  print(zukunft);
}

Der Code generiert ein Future mit dem Wert 14, was von Dart als ein Integerwert übersetzt wird. Anschliessend wird das Ergebnis dieses Future's, 14, der Variable zukunft zugewiesen.
Der folgende Versuch das Ergebnis mit einer print(...) Funktion auszudrucken wird scheitern ! 
Warum ?: Die print Funktion wird ausgeführt, obwohl das Ergebnis des Futures noch nicht vorliegt ! Im DartPad erhalten wir als Ergebnis: Instance of '_Future<int>'
Sie sehen die Problematik ?

Natürlich gibt es Abhilfe für dieses Problem. Die erste Lösung:

void main() {
  var zukunft = Future.value(14).then((ergebnis) => print(ergebnis));
}

Von Haus aus bietet Dart die Möglichkeit mit dem Ergebnis eines Futures umzugehen. Mit .then(...) können Sie festlegen, wie das Ergebnis des Futures weiter verarbeitet wird!
Dabei ist der Inhalt von .then(...) wiederum eine Funktion, diese kann in der Fat Arrow Schreibweise wie oben implementiert sein, oder in der Langform (...){...}. Um die zeitliche Abfolge zu verstehen testen Sie diesen Code im DartPad:


void main() {
  var zukunft = Future.value(14).then((ergebnis) => print(ergebnis));
  print('Mein Ausdruck');
  print(zukunft);
}

Sie werden sehen das zuerst "Mein Ausdruck" in die Konsole gedruckt wird, anschliessend 'Instance of '_Future<void>' und erst dann die 14

Jetzt ist es aber durchaus möglich, das Sie ein Future als Ergebnis bekommen, auf das Sie warten möchten oder müssen. Auch hier hat Dart eine Lösung:

void main() async {
  int zukunft;
  zukunft = await Future.value(14);
  print('Mein Ausdruck');
  print(zukunft);
}

Die wichtigsten Neuerungen im Code sind async und await. Mit async kennzeichnen Sie die ganze main Funktion als asynchron und mit await warten Sie das Ergebnis des Future's ab. 
Im Code oben wird korrekt zuerst "Mein Ausdruck" in die Konsole gedruckt, dann die 14 . Was passiert wenn wir den asynchronen Code in eine eigene Funktion packen ? :

void meineZukunft(zukunft)async{
  int zahl1 = zukunft;
  zukunft = await Future.value(zahl1);
  print(zukunft);
}

void main(){
  
 int zahl = 14;
 meineZukunft(zahl);
 print('Mein Text');
}

Wenn Sie den Code im DartPad ausführen werden Sie sehen, das zuerst wieder "Mein Text" in die Konsole gedruckt wird. Das ist auch richtig, schließlich haben wir die Funktion meineZukunft als asynchron markiert.
Wenn Dart den Code verarbeitet, wird die Funktion aufgerufen, aber nicht Ihre Beendigung abgewartet.

Ich denke das Prinzip hinter Future sollte klar sein. Vertiefende Informationen zur Future Klasse entnehmen Sie wie immer der hervorragenden Dokumentation von Dart. Bis bald.

Kommentare

Beliebte Posts aus diesem Blog

Material Design in Flutter Teil 2

Flutter -- ohne Dart geht es nicht 2 -- einfache Variablen Typen

Flutter -- Tutorial Teil 6 Provider Part 2