JavaScript – von Callbacks zu async/await

Blog

JavaScript ist synchron. Dies bedeutet, dass Ihr Codeblock nach der Bestellung ausgeführt wird Heben . Bevor der Code ausgeführt wird, |_+_| und |_+_| Erklärungen werden an die Spitze ihres Geltungsbereichs gehoben.



Dies ist ein Beispiel für einen synchronen Code:






var

Dieser Code protokolliert zuverlässig 1 2 3'.



Asynchrone Anforderungen warten, bis ein Timer beendet ist oder eine Anforderung reagiert, während der Rest des Codes weiter ausgeführt wird. Dann, wenn die Zeit reif ist a zurückrufen werden diese asynchronen Anforderungen in Aktion treten.



Dies ist ein Beispiel für einen asynchronen Code:






function

Dies wird tatsächlich 1 3 2 protokollieren, da die 2 auf einem |_+_| . liegt die in diesem Beispiel erst nach zwei Sekunden ausgeführt wird. Ihre Anwendung wartet nicht, bis die zwei Sekunden abgeschlossen sind. Stattdessen führt es den Rest des Codes weiter aus und kehrt nach Ablauf des Timeouts zu afterTwoSeconds zurück.

Sie fragen sich vielleicht, warum ist das nützlich? oder Wie kann ich meinen asynchronen Code synchronisieren?. Hoffentlich kann ich Ihnen die Antworten zeigen.

Das Problem

Nehmen wir an, unser Ziel ist es, nach einem GitHub-Benutzer zu suchen und alle Repositorys dieses Benutzers zu erhalten. Die Sache ist die, wir kennen den genauen Namen des Benutzers nicht. Wir müssen also alle Benutzer mit ähnlichem Namen und ihre jeweiligen Repositorys auflisten.

Muss nicht super schick sein, sowas

In diesen Beispielen verwendet der Anforderungscode XHR ( XMLHttpRequest ). Sie können es durch jQuery |_+_| . ersetzen oder der neuere native Ansatz namens |_+_|. Beide geben Ihnen die Versprechen aus dem Tor heraus.

Es wird sich je nach Ansatz leicht ändern, aber als Starter:

console.log('1') console.log('2') console.log('3')

Denken Sie daran, dass in diesen Beispielen der wichtige Teil nicht das Endergebnis des Codes ist. Stattdessen sollte es Ihr Ziel sein, die Unterschiede der Ansätze zu verstehen und wie Sie diese für Ihre Entwicklung nutzen können.

Zurückrufen

Sie können eine Referenz einer Funktion in einer Variablen speichern, wenn Sie JavaScript verwenden. Dann können Sie sie als Argumente einer anderen Funktion verwenden, um sie später auszuführen. Das ist unser Rückruf.

Ein Beispiel wäre:

console.log('1') setTimeout(function afterTwoSeconds() { console.log('2') }, 2000) console.log('3')

Verwenden der |_+_| um unser Problem zu lösen, können wir so etwas mit dem |_+_| . machen Funktion, die wir zuvor definiert haben:

setTimeout

Unsere Funktion für die Anfrage akzeptiert nun ein |_+_| so dass, wenn ein |_+_| gemacht wird, wird sie im Fehler- und Erfolgsfall aufgerufen.

$.ajax

Das aufschlüsseln:

  • Wir stellen eine Anfrage, um die Repositorys eines Benutzers zu erhalten
  • Nachdem die Anfrage abgeschlossen ist, verwenden wir Rückruf |_+_|
  • Wenn kein Fehler auftritt, analysieren wir unsere Serverantwort mit |_+_| . in ein Objekt
  • Dann iterieren wir unsere Benutzerliste, da sie mehr als eine haben kann
  • Für jeden Benutzer fordern wir seine Repository-Liste an.
  • Wir verwenden die URL, die pro Benutzer in unserer ersten Antwort zurückgegeben wurde
  • Wir nennen |_+_|als URL für unsere nächsten Anfragen oder von der ersten Antwort
  • Wenn die Anfrage den Rückruf abgeschlossen hat, rufen wir an
  • Dadurch wird entweder der Fehler oder die Antwort mit der Liste der Repositorys für diesen Benutzer behandelt

Notiz : Das Senden des Fehlers zuerst als Parameter ist eine gängige Praxis, insbesondere bei Verwendung von Node.js.

Ein vollständigerer und lesbarerer Ansatz wäre eine Fehlerbehandlung. Wir würden den Rückruf getrennt von der Anfrageausführung halten.

Etwas wie das:

fetch

Dies führt zu Problemen wie Renn- und Fehlerbehandlungsproblemen. Rennen passieren, wenn Sie nicht kontrollieren, welcher Benutzer Sie zuerst bekommen. Wir fordern die Informationen für alle von ihnen an, falls es mehr als eine gibt. Wir berücksichtigen keine Bestellung. Zum Beispiel kann Benutzer 10 zuerst kommen und Benutzer 2 zuletzt. Wir haben eine mögliche Lösung später im Artikel.

Das Hauptproblem bei Callbacks besteht darin, dass die Wartung und Lesbarkeit mühsam werden können. Es ist irgendwie schon und der Code tut kaum etwas. Dies ist bekannt als Rückruf Hölle die mit unserem nächsten Ansatz vermieden werden können.

bestes vscode-theme 2021

Versprechen

Verspricht, dass Sie Ihren Code lesbarer machen können. Ein neuer Entwickler kann zur Codebasis kommen und eine klare Ausführungsreihenfolge Ihres Codes sehen.

Um ein Versprechen zu erstellen, können Sie Folgendes verwenden:

// url argument can be something like 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) { if (xhr.readyState === 4) { if (xhr.status === 200) { // Code here for the server answer when successful } else { // Code here for the server answer when not successful } } } xhr.ontimeout = function () { // Well, it took to long do some code here to handle that } xhr.open('get', url, true) xhr.send(); }

Lass es uns zerlegen:

  • Ein Promise wird mit einem |_+_| . initialisiert das hat |_+_| und |_+_| Aussagen
  • Machen Sie Ihren asynchronen Code im |_+_| Funktion
  • |_+_| wenn alles wie gewünscht läuft
  • Sonst |_+_|
  • Wenn ein |_+_| gefunden wird|_+_| Methode wird dafür ausgeführt |_+_| Wenn ein |_+_| gefunden wird |_+_| wird ausgelöst

Dinge zu beachten:

  • |_+_| und |_+_| nur einen Parameter akzeptieren
  • |_+_| sendet nur 'yey' an die |_+_| Rückruffunktion
  • Wenn Sie mehrere |_+_| . verketten Fügen Sie ein |_+_| . hinzu wenn du das nächste |_+_| . willst Wert darf nicht |_+_| . sein
  • Wenn ein |_+_| wird erwischt mit |_+_| wenn du ein |_+_| . hast daran gekettet
  • Es wird trotzdem ausgeführt, dass |_+_| Sie können die |_+_| . sehen als immer ausgeführt und Sie können ein Beispiel in diesem überprüfen Kommentar
  • Mit einer Kette an |_+_| wenn beim ersten ein Fehler auftritt
  • Es überspringt nachfolgende |_+_| bis es ein |_+_| . findet
  • Ein Versprechen hat drei Zustände
  • steht aus
  • Beim Warten auf ein |_+_| oder |_+_| passieren
  • aufgelöst
  • hat abgelehnt
  • Einmal in einem |_+_| oder |_+_| Zustand
  • Es kann nicht geändert werden

Notiz : Sie können Versprechen ohne die Funktion zum Zeitpunkt der Deklaration erstellen. Die Art und Weise, wie ich es zeige, ist nur eine übliche Art, es zu tun.

Theorie, Theorie, Theorie … ich bin verwirrt, könnte man sagen.

Lassen Sie uns unser Anfragebeispiel mit einem Versprechen verwenden, um zu versuchen, die Dinge aufzuklären:

// Execute the function 'doThis' with another function as parameter, in this case 'andThenThis'. doThis will execute whatever code it has and when it finishes it should have 'andThenThis' being executed. doThis(andThenThis) // Inside of 'doThis' it's referenced as 'callback' which is just a variable that is holding the reference to this function function andThenThis() { console.log('and then this') } // You can name it whatever you want, 'callback' is common approach function doThis(callback) { console.log('this first') // the '()' is when you are telling your code to execute the function reference else it will just log the reference callback() }

In diesem Szenario, wenn Sie |_+_| . ausführen es wird so etwas zurückgeben:

Ein Versprechen, das noch gelöst oder abgelehnt werden muss

callback

Auf diese Weise lösen wir Rennsport und einige der Fehlerbehandlungsprobleme. Der Code ist noch etwas verworren. Aber es ist eine Möglichkeit, Ihnen zu zeigen, dass dieser Ansatz auch zu Lesbarkeitsproblemen führen kann.

Eine schnelle Lösung wäre, die Rückrufe wie folgt zu trennen:

request

Indem du dir ansiehst, was |_+_| wartet der Reihe nach mit dem |_+_| Sie können ein Gefühl dafür bekommen, was wir von diesem Codeblock erwarten. Alles ist mehr oder weniger durch Verantwortung getrennt.

Dies kratzt an der Oberfläche dessen, was Versprechen sind. Um einen guten Einblick in ihre Funktionsweise zu erhalten, kann ich dies nicht genug empfehlen Artikel .

Generatoren

Ein anderer Ansatz besteht darin, die Generatoren zu verwenden. Dies ist ein bisschen weiter fortgeschritten. Wenn Sie also gerade erst anfangen, können Sie gerne zum nächsten Thema springen.

Eine Verwendung für Generatoren besteht darin, dass Sie asynchronen Code haben, der wie Sync aussieht.

Sie werden durch ein |_+_| . dargestellt in einer Funktion und sehen ungefähr so ​​aus:

function request(url, callback) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) { if (xhr.readyState === 4) { if (xhr.status === 200) { callback(null, xhr.response) } else { callback(xhr.status, null) } } } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

Anstatt mit einem |_+_| zurückzukehren, haben Generatoren ein |_+_| Stellungnahme. Es stoppt die Funktionsausführung, bis ein |_+_| ist für diese Funktionsiteration gemacht. Es ist ähnlich wie |_+_| Versprechen, das nur ausgeführt wird, wenn gelöst zurückkommt.

Unsere Anfragefunktion würde so aussehen:

norton.com/setup anmelden
callback

Wir wollen die |_+_| als Argument. Aber anstatt die Anfrage von vornherein auszuführen, wollen wir sie nur, wenn wir einen Rückruf haben, um die Antwort zu bearbeiten.

Unsere |_+_| wäre so etwas wie:

request

Es wird:

  • Warte bis zum ersten |_+_| ist vorbereitet
  • Geben Sie ein |_+_| . zurück Referenz erwartet ein |_+_| zum ersten |_+_| Unsere |_+_| Funktion akzeptiert ein |_+_| und gibt ein |_+_| . zurück das erwartet ein |_+_|
  • Erwarte ein |_+_| wird im nächsten |_+_| . gesendet
  • Iteriere über |_+_|
  • Warte auf ein |_+_| für jeden der |_+_|
  • Geben Sie ihre jeweilige Callback-Funktion zurück

Eine Ausführung davon wäre also:

const userGet = `https://api.github.com/search/users?page=1&q=daspinola&type=Users` request(userGet, function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) { request(user.repos_url, function handleReposList(err, repos) { if (err) throw err // Handle the repositories list here }) }) })

Wir könnten die Callback-Funktionen wie zuvor trennen. Sie haben den Deal inzwischen bekommen, ein Imbiss ist, dass wir jetzt jede einzelne Benutzer-Repository-Liste einzeln behandeln können.

Ich habe gemischte Fällung über Generatoren. Einerseits kann ich mir anhand des Generators ein Bild davon machen, was vom Code erwartet wird.

Aber seine Ausführung hat ähnliche Probleme wie die Callback-Hölle.

wie man Hakenmünzen kauft

Mögen asynchron/warten , ein Compiler wird empfohlen. Dies liegt daran, dass es in älteren Browserversionen nicht unterstützt wird.

Ist meiner Erfahrung nach auch nicht so üblich. Daher kann es in Codebasen, die von verschiedenen Entwicklern gepflegt werden, zu Verwirrung führen.

Einen tollen Einblick in die Funktionsweise von Generatoren findet ihr hier Artikel. Und hier ist noch eine tolle Ressource .

Asynchron/Warten

Diese Methode scheint eine Mischung aus Generatoren mit Versprechen zu sein. Sie müssen Ihrem Code nur mitteilen, welche Funktionen |_+_| sein sollen. Und welcher Teil des Codes muss |_+_| dafür |_+_| beenden.

handleUsersList

In diesem Szenario:

  • Wir haben |_+_| als asynchrone Funktion
  • Wir sagen unserem Code, dass er auf die |_+_| . warten soll oder |_+_| für unsere Versprechen-Funktion |_+_|
  • Es wird nur in der |_+_| . enden wenn die |_+_| Operationen beendet
  • In diesem Fall gibt es nur einen

Anwenden auf unsere |_+_| wir belassen es als |_+_| wie vorhin gesehen:

JSON.parse

Wir erstellen unsere |_+_| Funktion mit den benötigten Waits wie folgt:

repos_url

Jetzt haben wir also ein asynchrones |_+_| Funktion, die die Anfragen verarbeitet. Im |_+_| . wird ein weiterer Async benötigt damit wir die Liste von |_+_| . haben für jeden Benutzer zu manipulieren.

Wir nennen es wie folgt:

try { request(userGet, handleUsersList) } catch (e) { console.error('Request boom! ', e) } function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) { request(user.repos_url, handleReposList) }) } function handleReposList(err, repos) { if (err) throw err // Handle the repositories list here console.log('My very few repos', repos) }

Dieser und der Versprechensansatz sind meine Favoriten, da der Code leicht zu lesen und zu ändern ist. Sie können mehr über Async/Warten lesen. Hier .

Ein Nachteil der Verwendung von async/await ist, dass es im Front-End von älteren Browsern oder im Back-End nicht unterstützt wird. Sie müssen den Knoten 8 verwenden.

Sie können einen Compiler wie verwenden Babel um das zu lösen.

Lösung

Du kannst das ... sehen Endecode unser ursprüngliches Ziel mit async/await in diesem Snippet zu erreichen.

Eine gute Sache ist, es selbst in den verschiedenen Formen auszuprobieren, auf die in diesem Artikel verwiesen wird.

Abschluss

Je nach Szenario verwenden Sie möglicherweise Folgendes:

  • asynchron/warten
  • Rückrufe
  • mischen

Es liegt an Ihnen, was Ihren Zwecken entspricht. Und was ermöglicht es Ihnen, den Code so zu pflegen, dass er für andere und Ihr zukünftiges Ich verständlich ist.

Notiz: Jeder der Ansätze wird etwas weniger ausführlich, wenn die Alternativen für Anfragen wie |_+_| . verwendet werden und |_+_|.

Lassen Sie mich wissen, was Sie anders machen würden und was Sie gefunden haben, um jeden Ansatz lesbarer zu machen.

#javascript #web-entwicklung

medium.freecodecamp.org

JavaScript – von Callbacks zu async/await

JavaScript – von Callbacks über Async bis hin zu Wait. JavaScript ist synchron. Dies bedeutet, dass es Ihren Codeblock nach dem Hochziehen auftragsgemäß ausführt. Bevor der Code ausgeführt wird, werden var- und Funktionsdeklarationen an den Anfang ihres Gültigkeitsbereichs gehoben