Asynchronus JavaScript

Mit Ecma-Script8 (ES8) haben wir eine Möglichkeit, Code, der asynchron ist, lesbarer zu schreiben und der sogenannten "Callback-Hell" zu entkommen: Die Rettung lautet Async / Await. Um Async / Await verstehen zu können, müssen wir jedoch zuerst Promises verstehen. Wir nutzen diese Techniken, um den asynchronen Code, der sequentiell in Javascript ausgeführt wird, wie bspw. API-Aufrufe von Drittanbietern, mühsame I/O-Operationen und andere CPU-intensive/blockierende Aufgaben, zu verarbeiten.

Working with Promises


Um den Code cleaner zu schreiben und damit lesbarer zu machen gibt es Promises. Ein Promise ist ein Objekt, das synchron von einer asynchronen Funktion zurückgegeben werden kann. Das Promise befindet sich in einem von drei möglichen Zuständen:

Behoben (resolved): Ein Promise konnte erfolgreich Daten abrufen oder einen Wert abrufen.

Abgelehnt (rejected): Ein Promise konnte aufgrund eines Fehlers oder Problems keine Daten abrufen.

Ausstehend (pending): Ausgangszustand, noch nicht gelöst oder abgelehnt. In diesem Zuge arbeiten wir mit .then und .catch. Das .then wird dann verkettet, um bei Erfolg eine Funktion auszuführen, und ein .catch wird hinzugefügt, um eine Fehlerbehandlung bereitzustellen.

    Beispiel
  • fakeRequestPromise('google.com/api/coffee/page1')
  • .then((data) => {
  • console.log("It worked!!(page1)")
  • console.log(data)
  • return fakeRequestPromise('google.com/api/coffee/page2')
  • })
  • .then((data) => {
  • console.log("It worked!!(page2)")
  • console.log(data)
  • return fakeRequestPromise('google.com/api/coffee/page3')
  • })
  • .then((data) => {
  • console.log("It worked!!(page3)")
  • console.log(data)
  • })
  • .catch((err) => {
  • console.log("Oh no, a request failed!")
  • console.log(err)
  • })

Writing Promises


Wenn wir in einer Funktion "return new Promise((resolve, reject) => {" einbringen, gibt uns dies ein Promise zurück. Ein Promise-Konstruktor übernimmt eine Funktion, die zwei Parameter akzeptiert: Reject und Resolve.

    Beispiel
  • const fakeRequest = (url) => {
  • return new Promise ((resolve, reject) => {
  • const rand =Math.random();
  • setTimeout(() =>{
  • if (rand < 0.7){
  • resolve ('Your fake data here');
  • }
  • reject('Request Error!')
  • }, 1000)
  • })
  • }

  • fakeRequest('/dogs/1')
  • .then((data) => {
  • console.log("Done with request!")
  • console.log('here is your data:', data)
  • })
  • .catch((err) => {
  • console.log("Oh no", err)
  • console.log(err)
  • })
    Anderes Beispiel
  • const delayedColorChange = (color,delay) => {
  • return new Promise ((resolve, reject) => {
  • setTimeout(() =>{
  • document.body.style.backgroundColor = color;
  • resolve ();
  • }, delay)
  • })
  • }


  • delayedColorChange('red', 1000)
  • .then(() => delayedColorChange('orange', 1000))
  • .then(() => delayedColorChange('yellow', 1000))
  • .then(() => delayedColorChange('green', 1000))
  • .then(() => delayedColorChange('blue', 1000))
  • .then(() => delayedColorChange('indigo', 1000))
  • .then(() => delayedColorChange('violet', 1000))

Async & Await

Async-Await ist eine weitere Möglichkeit, Promises in JavaScript zu handhaben. Sie vereinfachen die Anwendung von Promises, sind allerdings kein vollständiger Ersatz für Promises. Sie ermöglichen die kollektive Verarbeitung einer Gruppe von Promises.

Async-Functions


Das Schlüsselwort async kann so "async function test()"" oder so "const test = async() =>{}"" platziert werden. Die Verwendung des Wortes async vor einer Funktion bedeutet, dass diese Funktion ein Promise zurückgibt. Die von dieser Funktion zurückgegebenen Werte werden automatisch in ein aufgelöstes Promise eingeschlossen. Wenn wir das Keyword "async" vor der Funktionsdefinition verwenden, können wir innerhalb der Funktion auch "await" verwenden.

Await-Keyword


Await kann nur innerhalb einer asynchronen Funktion verwendet werden. Wir können Async ohne Await verwenden, aber wir können Await nicht ohne Async verwenden. Await weist die JS-Engine an, zu warten, seine Aktivitäten zu unterbrechen, bis das von der asynchronen Funktion zurückgegebene Promise abgelehnt oder aufgelöst wird. Erst dann kann das nächste await verarbeitet werden. Await-Aufrufe laufen also immer nacheinander.
Übrigens: Wir können jedem einzelnen Await ein catch() hinzufügen, da es sich um ein ganz normales Promise handelt.

    Beispiel
  • const delayedColorChange = (color,delay) => {
  • return new Promise ((resolve, reject) => {
  • setTimeout(() =>{
  • document.body.style.backgroundColor = color;
  • resolve ();
  • }, delay)
  • })
  • }

  • async function rainbow(){
  • await delayedColorChange('red', 1000))
  • await delayedColorChange('orange', 1000)
  • await delayedColorChange('yellow', 1000)
  • await delayedColorChange('green', 1000)
  • await delayedColorChange('blue', 1000)
  • await delayedColorChange('indigo', 1000)
  • await delayedColorChange('violet', 1000)
  • return "All done!"
  • }


  • async function printRainbow(){
  • await rainbow();
  • console.log("End of rainbow!")
    Anderes Beispiel
  • const fakeRequest = (url) => {
  • return new Promise ((resolve, reject) => {
  • const delay =Math.floor(Math.random()*(4500)) +500;
  • setTimeout(() =>{
  • if (delay > 4000){
  • reject('Connection Timeout!')
  • } else {
  • resolve (`Here is your fake data from ${url}` );
  • }
  • }, delay)
  • })
  • }


  • async makeTwoRequests(){
  • try{
  • let data1 = await fakeRequest ('/page1');
  • console.log(data1);
  • let data2 = await fakeRequest ('/page2');
  • console.log(data2);
  • } catch (e){
  • console.log("Caught an error!");
  • console.log("error is", e);
  • }
  • }