Detaillierte Erklärung von JavaScript Promise und Async/Await

Detaillierte Erklärung von JavaScript Promise und Async/Await

Überblick

Generell ist das Abfragen von Netzwerk-API-Operationen bei der Entwicklung oft zeitaufwändig, d. h. das Warten auf eine Antwort kann einige Zeit in Anspruch nehmen. Um zu vermeiden, dass das Programm bei einer Anforderung nicht reagiert, ist die asynchrone Programmierung für Entwickler eine grundlegende Fähigkeit.

Beim Umgang mit asynchronen Operationen in JavaScript hören wir oft das Konzept „Promise“. Doch das Verständnis seiner Funktionsweise und seiner Anwendung kann abstrakt und schwer sein.

Vier Beispiele

In diesem Artikel verwenden wir eine praktische Methode, damit Sie die Konzepte und die Verwendung schneller verstehen. Anders als in vielen herkömmlichen Trocken-Tutorials beginnen wir daher mit den folgenden vier Beispielen:

  • Beispiel 1: Erklären Sie die Grundlagen von Promise anhand von Geburtstagen
  • Beispiel 2: Ein Zahlen-Ratespiel
  • Beispiel 3: Länderinformationen über die Web-API abrufen
  • Beispiel 4: Abrufen einer Liste der Nachbarländer eines Landes über die Web-API

Beispiel 1: Promise-Grundlagen anhand von Geburtstagen erklärt

Schauen wir uns zunächst die Grundform von Promise an.

Wenn ein Versprechen ausgeführt wird, wird es in drei Zustände unterteilt: ausstehend (in Ausführung), erfüllt (erfolgreich) und abgelehnt (fehlgeschlagen).

neues Versprechen (Funktion (auflösen, ablehnen) {
    if (/* asynchroner Vorgang erfolgreich*/) {
        resolve(value); //Ändern Sie den Status von Promise von padding auf guaranteed.
    } anders {
        reject(error); //Ändern Sie den Status von Promise von padding auf rejected
    }
})
Es gibt drei Prototypmethoden in der Implementierung: then, catch und finally
versprechen
.then((Ergebnis) => {
    //das Versprechen wird angenommen oder abgelehnt, um die Ausführung fortzusetzen})
.catch((Fehler) => {
    //Versprechen wird abgelehnt})
.schließlich (() => {
    //Wenn das Versprechen erfüllt ist, wird es trotzdem ausgeführt})

Nachdem wir nun die Grundform vorgestellt haben, schauen wir uns die folgenden Beispiele an.

Benutzergeschichte: Mein Freund Kayo hat mir versprochen, bei meiner Geburtstagsparty in zwei Wochen einen Kuchen für mich zu backen.

Wenn alles gut geht und Kayo nicht krank ist, bekommen wir eine bestimmte Menge Kuchen, aber wenn Kayo krank ist, haben wir keinen Kuchen. Aber mit oder ohne Kuchen, wir werden trotzdem eine Geburtstagsparty veranstalten.

Lassen Sie uns für dieses Beispiel die obige Hintergrundgeschichte in JS-Code übersetzen. Lassen Sie uns zunächst eine Funktion erstellen, die ein Promise zurückgibt.

const anMeinGeburtstag = (isKayoSick) => {
  returniere neues Promise((lösen, ablehnen) => {
    setzeTimeout(() => {
      wenn (!istKayoSick) {
        Entschlossenheit (2);
      } anders {
        reject(new Error("Ich bin traurig"));
      }
    }, 2000);
  });
};

In JavaScript können wir mit new Promise() ein neues Promise erstellen, das eine Funktion mit einem Parameter akzeptiert: (resolve, reject) => {}.

In dieser Funktion sind „Auflösen“ und „Ablehnen“ standardmäßig bereitgestellte Rückruffunktionen. Schauen wir uns den obigen Code genauer an.

Wenn wir die Funktion onMyBirthday 2000 ms später ausführen.

  • Wenn Kayo nicht krank ist, führen wir die Resolve-Funktion mit 2 als Parameter aus
  • Wenn Kayo krank ist, führen wir „reject“ mit „new Error("Ich bin traurig")“ als Argument aus. Obwohl Sie als Argument alles übergeben können, was Sie ablehnen möchten, wird empfohlen, ein Fehlerobjekt zu übergeben.

Da onMyBirthday() ein Promise zurückgibt, haben wir nun Zugriff auf die Methoden then, catch und finally. Wir können außerdem auf die Argumente zugreifen, die zuvor in „then“ und „catch“ zum Auflösen und Ablehnen übergeben wurden.

Lassen Sie uns das Konzept anhand des folgenden Codes verstehen

Wenn Kayo nicht krank gewesen wäre

anMeinGeburtstag(falsch)
  .then((Ergebnis) => {
    console.log(`Ich habe ${result} Kuchen`); // Konsole druckt „Ich habe 2 Kuchen“ 
  })
  .catch((Fehler) => {
    console.log(Fehler); // nicht ausgeführt})
  .finally(() => {
    console.log("Party"); // Die Konsole druckt "Party"
  });

Wenn Kayo krank ist

anMeinGeburtstag(true)
  .then((Ergebnis) => {
    console.log(`Ich habe ${result} Kuchen`); // nicht ausgeführt})
  .catch((Fehler) => {
    console.log(error); // Die Konsole druckt „Ich bin traurig“
  })
  .finally(() => {
    console.log("Party"); // Die Konsole druckt "Party"
  });

Ich glaube, dass Sie anhand dieses Beispiels das Grundkonzept von Promise verstehen können.

Beispiel 2: Ein Zahlen-Ratespiel

Grundvoraussetzungen:

  • Der Benutzer kann eine beliebige Zahl eingeben
  • Das System generiert zufällig eine Zahl von 1 bis 6
  • Wenn die vom Benutzer eingegebene Zahl mit der Zufallszahl des Systems übereinstimmt, erhält der Benutzer 2 Punkte
  • Wenn die vom Benutzer eingegebene Zahl um 1 von der Zufallszahl des Systems abweicht, erhält der Benutzer 1 Punkt, andernfalls erhält der Benutzer 0 Punkte
  • Benutzer können so lange spielen, wie sie möchten

Für die oben genannten Anforderungen erstellen wir zuerst eine enterNumber-Funktion und geben ein Promise zurück:

const Eingabenummer = () => {
  returniere neues Promise((lösen, ablehnen) => {
    // Beginnen Sie hier mit der Codierung });
};

Als erstes fragen wir den Benutzer nach einer Zahl und wählen zufällig eine Zahl zwischen 1 und 6 aus:

const Eingabenummer = () => {
  returniere neues Promise((lösen, ablehnen) => {
    const userNumber = Number(window.prompt("Geben Sie eine Zahl ein (1 - 6):")); // Fragen Sie den Benutzer nach einer Zahl const randomNumber = Math.floor(Math.random() * 6 + 1); // Wählen Sie eine Zufallszahl zwischen 1 und 6 });
};

Wenn der Benutzer einen Wert eingibt, der keine Zahl ist. In diesem Fall rufen wir die Ablehnungsfunktion auf und geben einen Fehler aus:

const Eingabenummer = () => {
  returniere neues Promise((lösen, ablehnen) => {
    const userNumber = Number(window.prompt("Geben Sie eine Zahl ein (1 - 6):")); // Fragen Sie den Benutzer nach einer Zahl const randomNumber = Math.floor(Math.random() * 6 + 1); // Wählen Sie eine Zufallszahl zwischen 1 und 6 if (isNaN(userNumber)) {
      reject(new Error("Falscher Eingabetyp")); // Wenn der vom Benutzer eingegebene Wert keine Zahl ist, wird eine Ausnahme ausgelöst und die Ablehnungsfunktion aufgerufen}
  });
};

Als nächstes müssen wir prüfen, ob userNumber gleich RanomNumber ist. Wenn ja, geben wir dem Benutzer 2 Punkte und können dann die Resolve-Funktion ausführen, indem wir ein Objekt { points: 2, randomNumber } übergeben.

Wenn sich die Benutzernummer um 1 von der Zufallsnummer unterscheidet, geben wir dem Benutzer 1 Punkt. Andernfalls geben wir dem Benutzer 0 Punkte.

returniere neues Promise((lösen, ablehnen) => {
  const userNumber = Number(window.prompt("Geben Sie eine Zahl ein (1 - 6):")); // Fragen Sie den Benutzer nach einer Zahl const randomNumber = Math.floor(Math.random() * 6 + 1); // Wählen Sie eine Zufallszahl zwischen 1 und 6 if (isNaN(userNumber)) {
    reject(new Error("Falscher Eingabetyp")); // Wenn der vom Benutzer eingegebene Wert keine Zahl ist, wird eine Ausnahme ausgelöst und die Ablehnungsfunktion aufgerufen}
 
  if (Benutzernummer === Zufallszahl) {
    // Wenn sie gleich sind, geben wir dem Benutzer 2 Punkte resolve({
      Punkte: 2,
      Zufallszahl,
    });
  } sonst wenn (
    Benutzernummer === Zufallszahl - 1 ||
    Benutzernummer === Zufallszahl + 1
  ) {
    // Wenn die Differenz zwischen userNumber und randomNumber 1 ist, dann geben wir dem Benutzer 1 Punkt resolve({
      Punkte: 1,
      Zufallszahl,
    });
  } anders {
    // Andernfalls erhält der Benutzer 0 Punkte resolve({
      Punkte: 0,
      Zufallszahl,
    });
  }
});

Als Nächstes erstellen wir eine weitere Funktion, um den Benutzer zu fragen, ob er das Spiel fortsetzen möchte:

const continueGame = () => {
  returniere neues Promise((auflösen) => {
    if (window.confirm("Möchten Sie fortfahren?")) { // Den Benutzer fragen, ob er das Spiel fortsetzen möchte resolve(true);
    } anders {
      Lösung (falsch);
    }
  });
};

Um zu verhindern, dass das Spiel zwangsweise beendet wird, verwendet das von uns erstellte Promise den Reject-Callback nicht.

Als nächstes erstellen wir eine Funktion zur Handhabung der Ratelogik:

const handleGuess = () => {
  enterNumber() // Gibt ein Promise-Objekt zurück.then((result) => {
      alert(`Dice: ${result.randomNumber}: du hast ${result.points} Punkte`); // Wenn „Resolve“ ausgeführt wird, erhalten wir die Punktzahl des Benutzers und die Zufallszahl // Fragen Sie den Benutzer, ob er das Spiel fortsetzen möchte continueGame().then((result) => {
        wenn (Ergebnis) {
          handleGuess(); // Wenn ja, wird das Spiel fortgesetzt } else {
          alert("Spiel endet"); // Wenn nicht, öffne das Feld zum Spielende}
      });
    })
    .catch((Fehler) => Warnung(Fehler));
};
 
handleGuess(); // HandleGuess-Funktion ausführen

Wenn wir hier die Funktion handleGuess aufrufen, gibt enterNumber() ein Promise-Objekt zurück.

Wenn der Promise-Status aufgelöst ist, rufen wir die then-Methode auf, um den Benutzer über das Rateergebnis und den Punktestand zu informieren und ihn zu fragen, ob er das Spiel fortsetzen möchte.

Wenn der Promise-Status abgelehnt wird, zeigen wir dem Benutzer eine Meldung an, dass die Eingabe falsch war.

Obwohl ein solcher Code das Problem lösen kann, ist er dennoch etwas schwer zu lesen. Lassen Sie uns hanldeGuess später umgestalten, um async/await zu verwenden.

Es gibt im Internet bereits viele Erklärungen zu async/await. Hier möchte ich es auf einfache und allgemeine Weise erklären: async/await ist eine Art syntaktischer Zucker, der komplexen und schwer verständlichen asynchronen Code in eine synchrone Syntax umwandeln kann.

Schauen wir uns zunächst den überarbeiteten Code an:

const handleGuess = async () => {
  versuchen {
    const result = await enterNumber(); // Statt der then-Methode müssen wir nur await vor promise setzen, um das Ergebnis direkt zu erhalten alert(`Dice: ${result.randomNumber}: you got ${result.points} points`);
 
    const isContinuing = warte auf continueGame();
 
    wenn (wird fortgesetzt) ​​{
      handleGuess();
    } anders {
      alert("Spiel endet");
    }
  } catch (error) { // Die Catch-Methode kann durch try, catch function alert(error); ersetzt werden.
  }
};

Indem wir das Schlüsselwort async vor der Funktion verwenden, erstellen wir eine asynchrone Funktion. Die Verwendung innerhalb der Funktion unterscheidet sich von vorher wie folgt:

  • Anders als bei der then-Funktion müssen wir nur das Schlüsselwort await vor das Promise setzen, um das Ergebnis direkt zu erhalten.
  • Wir können die Try-Catch-Syntax verwenden, um die Catch-Methode im Promise zu ersetzen.

Hier ist der vollständige Code nach unserem Refactoring als Referenz:

const Eingabenummer = () => {
  returniere neues Promise((lösen, ablehnen) => {
    const userNumber = Number(window.prompt("Geben Sie eine Zahl ein (1 - 6):")); // Fragen Sie den Benutzer nach einer Zahl const randomNumber = Math.floor(Math.random() * 6 + 1); // Das System wählt zufällig eine Zahl zwischen 1 und 6 aus if (isNaN(userNumber)) {
      reject(new Error("Falscher Eingabetyp")); // Gibt einen Fehler aus, wenn der Benutzer eine Zahl eingibt, die keine Ziffer ist}
 
    if (userNumber === randomNumber) { // Wenn der Benutzer die Zahl richtig errät, erhält er 2 Punkte resolve({
        Punkte: 2,
        Zufallszahl,
      });
    } sonst wenn (
      Benutzernummer === Zufallszahl - 1 ||
      Benutzernummer === Zufallszahl + 1
    ) { // Wenn sich userNumber von randomNumber um 1 unterscheidet, geben wir dem Benutzer 1 Punkt resolve({
        Punkte: 1,
        Zufallszahl,
      });
    } sonst { // Falsch, Punktzahl 0 resolve({
        Punkte: 0,
        Zufallszahl,
      });
    }
  });
};
 
const weiterSpiel = () => {
  returniere neues Promise((auflösen) => {
    if (window.confirm("Möchten Sie fortfahren?")) { // Den Benutzer fragen, ob er das Spiel fortsetzen möchte resolve(true);
    } anders {
      Lösung (falsch);
    }
  });
};
 
const handleGuess = async () => {
  versuchen {
    const result = await enterNumber(); // await ersetzt die then-Funktion alert(`Dice: ${result.randomNumber}: du hast ${result.points} Punkte`);
 
    const isContinuing = warte auf continueGame();
 
    wenn (wird fortgesetzt) ​​{
      handleGuess();
    } anders {
      alert("Spiel endet");
    }
  } catch (error) { // Die Catch-Methode kann durch try, catch function alert(error); ersetzt werden.
  }
};
 
handleGuess(); // HandleGuess-Funktion ausführen

Nachdem wir das zweite Beispiel abgeschlossen haben, fahren wir mit dem dritten Beispiel fort.

Beispiel 3: Länderinformationen über die Web-API abrufen

Beim Abrufen von Daten aus einer API machen Entwickler häufig guten Gebrauch von Promises. Wenn Sie https://restcountries.eu/rest/v2/alpha/cn in einem neuen Fenster öffnen, werden Ihnen die Länderdaten im JSON-Format angezeigt.

Mithilfe der Fetch-API können wir die Daten ganz einfach abrufen. Hier ist der Code:

const fetchData = async () => {
  const res = await fetch("https://restcountries.eu/rest/v2/alpha/cn"); // fetch() gibt ein Versprechen zurück, also müssen wir darauf warten
 
  const country = await res.json(); // res ist jetzt nur noch eine HTTP-Antwort, also müssen wir res.json() aufrufen
 
  console.log(Land); // Chinas Daten werden in der Entwicklerkonsole protokolliert
};
 
fetchData();

Nachdem wir nun über die benötigten Länderdaten verfügen, fahren wir mit unserer letzten Aufgabe fort.

Beispiel 4: Abrufen einer Liste der Nachbarländer eines Landes über die Web-API

Die folgende fetchCountry-Funktion ruft die Länderinformationen von der API in Beispiel 3 ab. Der Parameter alpha3Code ist der Ländercode des Landes. Der folgende Code

// Aufgabe 4: Informationen über die Nachbarländer Chinas einholen const fetchCountry = async (alpha3Code) => {
  versuchen {
    const res = warte auf Abruf(
      `https://restcountries.eu/rest/v2/alpha/${alpha3Code}`
    );
 
    const Daten = warte auf res.json();
 
    Daten zurückgeben;
  } Fehler abfangen {
    konsole.log(Fehler);
  }
};

Erstellen wir eine Funktion „fetchCountryAndNeighbors“, um die Informationen für China abzurufen, indem wir cn als Alpha-3-Code übergeben.

const fetchCountryAndNeighbors = async () => {
  const china = warte auf fetchCountry("cn");
 
  Konsole.log (China);
};
 
fetchCountryAndNeighbors();

In der Konsole schauen wir uns den Objektinhalt an:

Im Objekt gibt es eine Grenzeigenschaft, die eine Liste von Alpha3-Codes der Nachbarländer Chinas ist.

Versuchen wir nun, auf folgende Weise Informationen über die Nachbarländer zu erhalten.

const Nachbarn = china.borders.map((Grenze) => fetchCountry(Grenze));

Nachbarn ist ein Array von Promise-Objekten.

Beim Arbeiten mit einem Array von Promises müssen wir Promise.all verwenden.

const fetchCountryAndNeigbors = async () => {
  const china = warte auf fetchCountry("cn");
 
  const Nachbarn = warte auf Promise.all(
    china.borders.map((Grenze) => fetchCountry(Grenze))
  );
 
  console.log(Nachbarn);
};
 
fetchCountryAndNeigbors();

In der Konsole sollten wir eine Liste mit Länderobjekten sehen können.

Hier ist der gesamte Code für Beispiel 4 zu Ihrer Information:

const fetchCountry = async (alpha3Code) => {
  versuchen {
    const res = warte auf Abruf(
      `https://restcountries.eu/rest/v2/alpha/${alpha3Code}`
    );
    const Daten = warte auf res.json();
    Daten zurückgeben;
  } Fehler abfangen {
    konsole.log(Fehler);
  }
};
 
const fetchCountryAndNeigbors = async () => {
  const china = warte auf fetchCountry("cn");
  const Nachbarn = warte auf Promise.all(
    china.borders.map((Grenze) => fetchCountry(Grenze))
  );
  console.log(Nachbarn);
};
 
fetchCountryAndNeigbors();

Zusammenfassen

Nachdem Sie diese vier Beispiele durchgearbeitet haben, können Sie erkennen, dass Promises bei der Verarbeitung asynchroner Vorgänge oder Dingen, die nicht gleichzeitig geschehen, nützlich sind. Ich glaube, dass Ihr Verständnis mit kontinuierlicher Übung tiefer und stärker wird. Ich hoffe, dieser Artikel kann Ihnen helfen, Promise und Async/Await zu verstehen.

Hier ist der in diesem Artikel verwendete Code: https://files.cnblogs.com/files/powertoolsteam/Promise-Async-Await-main.zip

Oben finden Sie eine ausführliche Erläuterung von JavaScript Promise und Async/Await. Weitere Informationen zu JavaScript Promise und Async/Await finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • async/await und promise (Problem mit asynchronem Betrieb in nodejs)
  • Verstehen Sie das Versprechen von JavaScript gründlich
  • Detaillierte Erklärung der asynchronen Funktion in Javascript
  • Eine einfache und eingehende Studie zu Async und Await in JavaScript
  • Detaillierte Erklärung des Unterschieds zwischen Promise, Async und Await in Javascript

<<:  So konfigurieren Sie mehrere Tomcats mit Nginx-Lastausgleich unter Linux

>>:  So konfigurieren Sie die Datei My.ini bei der Installation der MySQL5.6.17-Datenbank

Artikel empfehlen

So verbergen Sie die Grenze/Trennlinie zwischen Zellen in einer Tabelle

Nur den oberen Rand anzeigen <table frame=above...

Häufige JavaScript-Speicherfehler und Lösungen

Inhaltsverzeichnis 1. Zeitüberwachung 2. Ereignis...

Detaillierte Erläuterung der MySQL-Transaktionsverwaltungsvorgänge

Dieser Artikel beschreibt die MySQL-Transaktionsv...

Vue3 (Teil 2) Integration von Ant Design Vue

Inhaltsverzeichnis 1. Integrieren Sie Ant Design ...

Semantik, Schreiben und bewährte Methoden für Link A

Die Semantik, der Schreibstil und die Best Practi...

Detaillierter Installationsprozess und Prinzip des Vue-Routers

Inhaltsverzeichnis 1. Implementierungsprinzip des...

Beispielcode eines CSS-responsiven Layoutsystems

Responsive Layoutsysteme sind in den heute gängig...

So begrenzen Sie die Anzahl der Datensätze in einer Tabelle in MySQL

Inhaltsverzeichnis 1. Lösung auslösen 2. Partitio...

Zwei Möglichkeiten zum Starten des Linux-Bootdienstes

Inhaltsverzeichnis rc.local-Methode chkconfig-Met...

So verwenden Sie Node zum Implementieren des statischen Datei-Cachings

Inhaltsverzeichnis Cache Klassifizierung des Cach...

Trash-Cli: Befehlszeilen-Papierkorb-Tool unter Linux

Ich glaube, jeder kennt den Papierkorb, da er bei...