Heim > Web-Frontend > js-Tutorial > Asynchrones JavaScript – Der Weg von Callbacks zu Async Await

Asynchrones JavaScript – Der Weg von Callbacks zu Async Await

Barbara Streisand
Freigeben: 2024-11-29 03:41:13
Original
897 Leute haben es durchsucht

Als Single-Thread-Sprache war JavaScript schon immer auf asynchrone Programmierung angewiesen, um zeitaufwändige Aufgaben zu bewältigen, ohne die Codeausführung zu blockieren. Im Laufe der Jahre haben sich die Ansätze zum Umgang mit Asynchronität in JavaScript erheblich weiterentwickelt und sind lesbarer, handhabbarer und leichter nachvollziehbar geworden. Lassen Sie mich Sie auf eine Reise durch die Geschichte des asynchronen JavaScript mitnehmen, von Rückrufen über Versprechen bis hin zu Async/Await.

Synchrones JavaScript: Die Geburt

In den Anfängen von JavaScript, vor der weit verbreiteten Einführung von Callbacks, wurde der meiste JavaScript-Code synchron geschrieben. Synchroner Code bedeutet, dass jede Operation nacheinander auf blockierende Weise ausgeführt wird. Wenn ein Vorgang mit langer Laufzeit festgestellt wurde, wurde die Ausführung des gesamten Skripts angehalten, bis dieser Vorgang abgeschlossen war.

Stellen Sie sich vor, Sie stehen an einem Fahrkartenschalter am Bahnhof und haben nur einen Fahrkartenverkäufer. Sie fordern ein Ticket an und der Ticketverkäufer beginnt mit der Bearbeitung Ihrer Anfrage. Im synchronen Modell müssten Sie am Schalter warten, bis der Ticketverkäufer Ihre Anfrage bearbeitet und Ihnen das Ticket aushändigt. In dieser Zeit kann niemand anderes bedient werden und der gesamte Ticketschalter ist gesperrt.

Asynchronous JavaScript - The Journey from Callbacks to Async Await

Hier ist ein Beispiel für synchronen JavaScript-Code:

console.log("Before operation"); 

// Simulating a long-running operation 
for (let i = 0; i < 1000000000; i++) { 
// Performing some computation 
} 

console.log("After operation");

Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

In diesem Code werden die console.log-Anweisungen der Reihe nach ausgeführt und der lang andauernde Vorgang (die for-Schleife) blockiert die Ausführung des Skripts, bis es abgeschlossen ist. Die Meldung „Nach dem Vorgang“ wird erst protokolliert, nachdem die Schleife beendet ist.

Das Problem mit synchronem Code

Obwohl synchroner Code einfach zu verstehen und zu begründen ist, wirft er mehrere Probleme auf, insbesondere wenn es um zeitaufwändige Vorgänge geht:

  1. Blockierung der Ausführung: Lang andauernde Vorgänge blockieren die Ausführung des gesamten Skripts, wodurch die Webseite oder Anwendung nicht mehr reagiert, bis der Vorgang abgeschlossen ist.
  2. Schlechte Benutzererfahrung: Das Blockieren der Ausführung kann zu einer schlechten Benutzererfahrung führen, da Benutzer warten müssen, bis Vorgänge abgeschlossen sind, bevor sie mit der Anwendung interagieren.
  3. Ineffiziente Ressourcennutzung: Synchroner Code ermöglicht keine effiziente Nutzung von Systemressourcen, da er keine anderen Aufgaben ausführen kann, während er auf den Abschluss eines Vorgangs wartet.

Um die Einschränkungen des synchronen Codes zu überwinden und ein besseres Benutzererlebnis zu bieten, wurden asynchrone Programmiertechniken eingeführt. Durch die asynchrone Programmierung können lang laufende Vorgänge im Hintergrund ausgeführt werden, ohne die Ausführung des restlichen Codes zu blockieren. Auf diese Weise wurde Callback eingeführt.

Rückrufe: Die frühen Tage

Rückrufe waren die primäre Möglichkeit, asynchrone Vorgänge abzuwickeln. Ein Rückruf ist einfach eine Funktion, die als Argument an eine andere Funktion übergeben wird und später ausgeführt wird, sobald der asynchrone Vorgang abgeschlossen ist.

Stellen Sie sich vor, Sie möchten eine Bahnfahrkarte kaufen. Sie gehen zum Ticketschalter am Bahnhof und beantragen ein Ticket für ein bestimmtes Ziel. Der Fahrkartenverkäufer nimmt Ihre Anfrage entgegen und bittet Sie zu warten, während er die Verfügbarkeit von Sitzplätzen im Zug prüft. Sie übermitteln ihnen Ihre Kontaktdaten und warten im Wartebereich. Sobald der Ticketverkäufer Ihre Anfrage bearbeitet hat und ein Sitzplatz verfügbar ist, ruft er Ihren Namen an, um Ihnen mitzuteilen, dass Ihr Ticket zur Abholung bereit ist. In dieser Analogie sind Ihre Kontaktinformationen der Rückruf – eine Möglichkeit für den Ticketverkäufer, Sie zu benachrichtigen, wenn die asynchrone Aufgabe (Prüfung der Sitzplatzverfügbarkeit und Ausstellung des Tickets) abgeschlossen ist.

Asynchronous JavaScript - The Journey from Callbacks to Async Await

So bezieht sich die Analogie auf Rückrufe in JavaScript:

  • Ein Zugticket anzufordern ist wie der Aufruf einer asynchronen Funktion, die einen Rückruf als Argument akzeptiert.
  • Die Bereitstellung Ihrer Kontaktinformationen an den Ticketverkäufer ist wie die Übergabe einer Rückruffunktion an die asynchrone Funktion.
  • Der Ticketverkäufer überprüft die Sitzplatzverfügbarkeit und bearbeitet Ihre Anfrage, gleicht dem asynchronen Vorgang, der ausgeführt wird.
  • Der Ticketverkäufer, der Ihren Namen ruft, wenn das Ticket fertig ist, ist so, als würde die Rückruffunktion mit dem Ergebnis des asynchronen Vorgangs aufgerufen.
  • Das Warten im Wartebereich ist so, als würde der Rest Ihrer Codeausführung fortgesetzt, während der asynchrone Vorgang verarbeitet wird.

Beim Callback-Ansatz stellen Sie eine Funktion (den Callback) bereit, die aufgerufen wird, sobald der asynchrone Vorgang abgeschlossen ist. Die asynchrone Funktion führt ihre Aufgabe aus und ruft dann den Rückruf mit dem Ergebnis oder Fehler auf, sodass Ihr Code das Ergebnis des asynchronen Vorgangs verarbeiten kann.

Hier ist ein Beispiel für einen API-Aufruf mithilfe von Rückrufen in Node.js:

console.log("Before operation"); 

// Simulating a long-running operation 
for (let i = 0; i < 1000000000; i++) { 
// Performing some computation 
} 

console.log("After operation");

Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

In diesem Beispiel haben wir eine fetchData-Funktion, die einen API-Aufruf simuliert. Als Argumente werden ein URL-Parameter und eine Rückruffunktion benötigt. Innerhalb der Funktion verwenden wir setTimeout, um eine Verzögerung von 1000 Millisekunden (1 Sekunde) zu simulieren, bevor die Rückruffunktion aufgerufen wird.

Die Callback-Funktion folgt der allgemeinen Konvention, einen Fehler als erstes Argument (err) und die Daten als zweites Argument (data) zu akzeptieren. In diesem Beispiel simulieren wir einen erfolgreichen API-Aufruf, indem wir den Fehler auf null setzen und ein Beispieldatenobjekt bereitstellen.

Um die fetchData-Funktion zu verwenden, rufen wir sie mit einer URL und einer Callback-Funktion auf. Innerhalb der Callback-Funktion prüfen wir zunächst, ob ein Fehler aufgetreten ist, indem wir das Argument err überprüfen. Wenn ein Fehler vorliegt, protokollieren wir ihn mit console.error in der Konsole und kehren zurück, um die weitere Ausführung zu stoppen.

Wenn kein Fehler aufgetreten ist, protokollieren wir die empfangenen Daten mithilfe von console.log in der Konsole.

Wenn Sie diesen Code ausführen, simuliert er einen asynchronen API-Aufruf. Nach einer Verzögerung von 1 Sekunde wird die Rückruffunktion aufgerufen und das Ergebnis in der Konsole protokolliert:

{ id: 1, name: 'John Doe' }

Dieses Beispiel zeigt, wie Rückrufe zur Verarbeitung asynchroner API-Aufrufe verwendet werden können. Die Rückruffunktion wird als Argument an die asynchrone Funktion (fetchData) übergeben und aufgerufen, sobald der asynchrone Vorgang abgeschlossen ist, entweder mit einem Fehler oder mit den resultierenden Daten.

Obwohl Rückrufe ihre Arbeit erledigten, hatten sie mehrere Nachteile:

Asynchronous JavaScript - The Journey from Callbacks to Async Await

  1. Callback Hell/ Pyramid of Doom: Die Verschachtelung mehrerer asynchroner Vorgänge führte zu tief verschachteltem und eingerücktem Code, was das Lesen und Warten erschwerte.
  2. Fehlerbehandlung: Die Behandlung von Fehlern auf jeder Verschachtelungsebene war umständlich und führte oft zu sich wiederholendem Code.
  3. Mangelnde Lesbarkeit: Die nichtlineare Natur von Rückrufen machte es schwieriger, dem Code zu folgen und darüber nachzudenken.

Versprechen: Ein Schritt nach vorne

Um den Herausforderungen mit Rückrufen zu begegnen, wurden in ES6 (ECMAScript 2015) Versprechen eingeführt. Ein Versprechen stellt den eventuellen Abschluss oder Misserfolg eines asynchronen Vorgangs dar und ermöglicht es Ihnen, Vorgänge miteinander zu verketten.

Stellen Sie sich ein Versprechen wie ein Zugticket vor. Wenn Sie ein Bahnticket kaufen, stellt das Ticket ein Versprechen der Eisenbahngesellschaft dar, dass Sie in den Zug einsteigen und Ihr Ziel erreichen können. Das Ticket enthält Informationen über den Zug, wie Abfahrtszeit, Strecke und Sitzplatznummer. Sobald Sie das Ticket haben, können Sie auf die Ankunft des Zuges warten und wenn dieser zum Einsteigen bereit ist, können Sie mit Ihrem Ticket in den Zug einsteigen.

In dieser Analogie ist das Zugticket das Versprechen. Es stellt den endgültigen Abschluss eines asynchronen Vorgangs (der Zugfahrt) dar. Sie behalten das Ticket (das Versprechensobjekt), bis der Zug bereit ist (der asynchrone Vorgang ist abgeschlossen). Sobald das Versprechen gelöst ist (der Zug ankommt), können Sie mit dem Ticket in den Zug einsteigen (auf den gelösten Wert zugreifen).

So bezieht sich die Analogie auf Versprechen in JavaScript:

  • Der Kauf des Zugtickets ist wie der Aufruf einer asynchronen Funktion, die ein Versprechen zurückgibt.
  • Das Zugticket selbst ist das Versprechensobjekt, das das zukünftige Ergebnis des asynchronen Vorgangs darstellt.
  • Das Warten auf die Ankunft des Zuges ist wie das Warten darauf, dass das Versprechen eingelöst oder abgelehnt wird.
  • Das Einsteigen in den Zug mit dem Ticket ist wie die Verwendung von .then(), um auf den aufgelösten Wert des Versprechens zuzugreifen.
  • Wenn der Zug abgebrochen wird (ein Fehler auftritt), ist das so, als würde das Versprechen abgelehnt, und Sie würden es mit .catch() handhaben.

Versprechen bieten eine strukturierte Möglichkeit, asynchrone Vorgänge abzuwickeln, sodass Sie mehrere Vorgänge miteinander verketten und Fehler besser verwalten können, genau wie ein Zugticket Ihnen bei der Organisation und Verwaltung Ihrer Zugfahrt hilft.

Asynchronous JavaScript - The Journey from Callbacks to Async Await

Hier ist ein Beispiel für einen API-Aufruf mithilfe von Versprechen:

console.log("Before operation"); 

// Simulating a long-running operation 
for (let i = 0; i < 1000000000; i++) { 
// Performing some computation 
} 

console.log("After operation");

Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

In diesem Code gibt die fetchData-Funktion ein Versprechen zurück. Der Versprechenskonstruktor übernimmt eine Funktion, die zwei Argumente akzeptiert: auflösen und ablehnen. Diese Funktionen werden verwendet, um den Status des Versprechens zu steuern.

Im Promise-Konstruktor simulieren wir einen API-Aufruf mit setTimeout, genau wie im vorherigen Beispiel. Anstatt jedoch eine Rückruffunktion aufzurufen, verwenden wir die Auflösungs- und Ablehnungsfunktionen, um das asynchrone Ergebnis zu verarbeiten.

Wenn ein Fehler auftritt (in diesem Beispiel simulieren wir ihn, indem wir die Fehlervariable überprüfen), rufen wir die Ablehnungsfunktion mit dem Fehler auf und geben an, dass das Versprechen abgelehnt werden soll.

Wenn kein Fehler auftritt, rufen wir die Auflösungsfunktion mit den Daten auf und geben an, dass das Versprechen mit den empfangenen Daten aufgelöst werden soll.

Um die fetchData-Funktion zu verwenden, verketten wir die Methoden .then() und .catch() mit dem Funktionsaufruf. Die Methode .then() wird verwendet, um den aufgelösten Wert des Versprechens zu verarbeiten, während die Methode .catch() verwendet wird, um eventuell auftretende Fehler zu verarbeiten.

Wenn das Versprechen erfolgreich aufgelöst wird, wird die .then()-Methode mit den aufgelösten Daten aufgerufen und wir protokollieren sie mit console.log in der Konsole.

Wenn ein Fehler auftritt und das Versprechen abgelehnt wird, wird die .catch()-Methode mit dem err-Objekt aufgerufen und wir protokollieren es mit console.error in der Konsole.

Die Verwendung von Versprechen bietet im Vergleich zu Rückrufen eine strukturiertere und lesbarere Möglichkeit, asynchrone Vorgänge abzuwickeln. Mit Versprechen können Sie mehrere asynchrone Vorgänge mit .then() miteinander verketten und Fehler mit .catch() zentraler behandeln.

Versprechen wurden bei Rückrufen in mehrfacher Hinsicht verbessert:

  1. Verkettung: Mit Promises konnten Sie mehrere asynchrone Vorgänge mithilfe von .then verketten, wodurch der Code besser lesbar und leichter zu befolgen war.
  2. Fehlerbehandlung: Promises stellte eine .catch-Methode bereit, um Fehler zentralisierter und effizienter zu behandeln.
  3. Lesbarkeit: Versprechen, dass asynchroner Code eher wie synchroner Code aussieht, was die Lesbarkeit verbessert.

Versprechen hatten jedoch immer noch einige Einschränkungen. Die Verkettung mehrerer Versprechen könnte immer noch zu tief verschachteltem Code führen, und die Syntax war nicht so sauber, wie sie sein könnte.

Async/Await: Der moderne Ansatz

Async/await, eingeführt in ES8 (ECMAScript 2017), basiert auf Versprechen und bietet eine synchroner aussehende Möglichkeit, asynchronen Code zu schreiben.

Mit async/await können Sie asynchronen Code schreiben, der wie synchroner Code aussieht und sich verhält. Es ist, als ob Sie einen persönlichen Assistenten hätten, der für Sie zum Ticketschalter geht. Sie warten einfach darauf, dass Ihr Assistent mit dem Ticket zurückkommt, und sobald er zurückkommt, können Sie Ihre Reise fortsetzen.

Hier ist ein Beispiel für einen API-Aufruf mit async/await:

console.log("Before operation"); 

// Simulating a long-running operation 
for (let i = 0; i < 1000000000; i++) { 
// Performing some computation 
} 

console.log("After operation");

Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

In diesem Code haben wir eine asynchrone Funktion namens fetchData, die einen URL-Parameter entgegennimmt, der den API-Endpunkt darstellt. Innerhalb der Funktion verwenden wir einen Try/Catch-Block, um alle Fehler zu behandeln, die während der API-Anfrage auftreten können.

Wir verwenden das Schlüsselwort „await“ vor der fetch-Funktion, um die Ausführung anzuhalten, bis das von fetch zurückgegebene Versprechen aufgelöst ist. Das bedeutet, dass die Funktion wartet, bis die API-Anfrage abgeschlossen ist, bevor sie mit der nächsten Zeile fortfährt.

Sobald die Antwort eingegangen ist, verwenden wir „await Response.json()“, um den Antworttext als JSON zu analysieren. Dies ist ebenfalls ein asynchroner Vorgang, daher verwenden wir „await“, um auf den Abschluss der Analyse zu warten.

Wenn die API-Anfrage und die JSON-Analyse erfolgreich sind, werden die Daten von der fetchData-Funktion zurückgegeben.

Wenn während der API-Anfrage oder der JSON-Analyse ein Fehler auftritt, wird dieser vom Catch-Block abgefangen. Wir protokollieren den Fehler mithilfe von console.error in der Konsole und lösen den Fehler mithilfe von throw err erneut aus, um ihn an den Aufrufer weiterzugeben.

Um die fetchData-Funktion zu verwenden, haben wir eine asynchrone Funktion namens main. Innerhalb von main geben wir die URL des API-Endpunkts an, von dem wir Daten abrufen möchten.

Wir verwenden „await fetchData(url)“, um die fetchData-Funktion aufzurufen und darauf zu warten, dass sie die Daten zurückgibt. Wenn die API-Anfrage erfolgreich ist, protokollieren wir die empfangenen Daten in der Konsole.

Wenn während der API-Anfrage ein Fehler auftritt, wird dieser vom Catch-Block in der Hauptfunktion abgefangen. Wir protokollieren den Fehler mit console.error.

in der Konsole

Zuletzt rufen wir die Hauptfunktion auf, um die Ausführung des Programms zu starten.

Wenn Sie diesen Code ausführen, wird mithilfe der Abruffunktion eine asynchrone API-Anfrage an die angegebene URL gesendet. Wenn die Anfrage erfolgreich ist, werden die empfangenen Daten in der Konsole protokolliert. Wenn ein Fehler auftritt, wird dieser ebenfalls abgefangen und protokolliert.

Die Verwendung von async/await mit der Fetch-Funktion bietet eine saubere und lesbare Möglichkeit, asynchrone API-Anfragen zu verarbeiten. Sie können damit asynchronen Code schreiben, der wie synchroner Code aussieht und sich verhält, wodurch er einfacher zu verstehen und zu warten ist.

Async/await bietet mehrere Vorteile:

  1. Prägnanter Code: Mit Async/await können Sie asynchronen Code schreiben, der wie synchroner Code aussieht und sich auch so anfühlt, wodurch er prägnanter und lesbarer wird.
  2. Fehlerbehandlung: Async/await verwendet Try/Catch-Blöcke zur Fehlerbehandlung, was im Vergleich zu .catch mit Versprechen eine vertrautere und intuitivere Methode zur Fehlerbehandlung darstellt.
  3. Lesbarkeit: Async/await erleichtert das Verständnis und die Überlegung von asynchronem Code, insbesondere für Entwickler, die mit synchroner Programmierung vertraut sind.

Abschluss

Asynchronous JavaScript - The Journey from Callbacks to Async Await

Zusammenfassend lässt sich sagen, dass die Entwicklung von asynchronem JavaScript, von Callbacks über Promises bis hin zu Async/Await, eine Reise hin zu besser lesbarem, verwaltbarem und wartbarerem asynchronem Code war. Jeder Schritt baut auf dem vorherigen auf, beseitigt die Einschränkungen und verbessert die Entwicklererfahrung.

Async/await ist heute weit verbreitet und hat sich zur bevorzugten Methode zur Verarbeitung asynchroner Vorgänge in JavaScript entwickelt. Es ermöglicht Entwicklern, asynchronen Code zu schreiben, der sauber, prägnant und leicht verständlich ist, was es zu einem wertvollen Werkzeug im Werkzeugkasten jedes JavaScript-Entwicklers macht.

Das obige ist der detaillierte Inhalt vonAsynchrones JavaScript – Der Weg von Callbacks zu Async Await. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage