
kontaktiere uns


Von Webanwendungen bis hin zu Servern und mobilen Apps, von kleinen Programmen bis hin zu großen Projekten — JavaScript ist überall. Es ist die erste Wahl, um jedes Projekt anzunehmen, denn, nun ja, es ist 2020 und JS ist eine noch ausgereiftere Sprache, die von einer riesigen Community unterstützt wird.
In JavaScript läuft der gesamte Code synchron in der Event-Schleife, die sequentiell kleine Teile unseres Programms ausführt. In der Ereignisschleife wird jede Iteration als „ankreuzen“ und läuft, bis die Warteschlange leer ist. Jeder Chunk hat eine „ankreuzen“ zu verarbeiten und nachdem es abgeschlossen ist, beginnt das nächste. Für kleine Anwendungen ist das ausreichend, aber da wir anfangen, umfangreichere Operationen durchzuführen, die mehr Zeit in Anspruch nehmen, wie z. B. der Zugriff auf eine Datenbank oder das Abrufen von Daten über das Internet, benötigen wir bessere Mechanismen, um sie zu handhaben.
Im Laufe der Jahre entstanden Muster und Bibliotheken in der JS-Ökosystem um asynchrone Programmierung wie Callbacks, Ereignisse, Versprechen, Generatoren, Async/Await, Webworker und Pakete in der NPM-Registrierung wie async, bluebird, co oder RxJS zu handhaben.
Was Frontend-Entwickler betrifft, so müssen wir je nach Framework, an dem wir arbeiten, möglicherweise unterschiedliche Muster verwenden, um die herausfordernden Probleme des Alltags zu lösen. Wenn wir die verfügbaren Tools in der JavaScript-Welt kennen, können wir für jedes Problem die beste Lösung auswählen.
Sie fragen sich vielleicht, ob dieser Leitfaden nur für die Webentwicklung bestimmt ist? Nein, die meisten dieser Muster werden in allen JavaScript-Umgebungen und -Plattformen verwendet. Daher ist es für jeden Entwickler immer wertvoll zu wissen, wie sie funktionieren.
In JavaScript sind Funktionen erstklassige Objekte und ein Rückruf ist nur eine Funktion, die als Argument an eine andere Funktion übergeben wird. Der Callback, auch bekannt als Funktionen höherer Ordnung, sollte immer dann aufgerufen werden, wenn die asynchrone Arbeit abgeschlossen ist.
Da Callbacks nur Funktionen sind, werden sie von allen Umgebungen unterstützt, in denen JavaScript ausgeführt wird, von unseren Browsern bis hin zu Servern, auf denen JavaScript ausgeführt wird Node.js. Dieses einfache, aber leistungsstarke Muster ist für Asynchronität von grundlegender Bedeutung. Es hat jedoch auch seine Nachteile.
Wenn Projekte wachsen und wir anfangen müssen, komplexeren Code zu erstellen, wird es schwieriger, generische Lösungen in unseren Programmen zu implementieren, wodurch sie schwieriger zu lesen und zu verwalten sind. Wenn das passiert, beginnen wir, die Pyramidenform von `}) `zu haben, ähnlich dem, was wir im folgenden Beispiel sehen können.
Dies ist normalerweise bekannt als „Rückruf-Hölle“.
Das Schlimmste, was wir mit Rückrufen haben können, ist jedoch die Umkehrung der Kontrolle. In diesem Fall geben wir die Kontrolle über den Programmablauf an andere Parteien ab, was es schwierig (oder sogar unmöglich!) macht um es richtig zu testen.
Eine ereignisgesteuerte Architektur kann auch zum Schreiben von asynchronem Javascript-Code verwendet werden. Diese Architektur besteht aus einem Event-Emitter mit einem entsprechenden Event-Listener, der Ereignisse sendet, wenn der asynchrone Code abgeschlossen ist. Das Senden verschiedener Ereignistypen ermöglicht unterschiedliche Rückrufe für jeden Typ von Listenern. Ein grundlegendes Beispiel und ein wirklich wichtiger Teil der Frontend-Entwicklung ist das Anfordern von Daten über das Internet. Um das zu erreichen, könnten wir das verwenden XMLHttpAnfrage Objekt, das bei der AJAX-Programmierung häufig verwendet wird.
Für das XMLHttpRequest-Objekt sind bereits einige Event-Listener definiert, um den Anforderungsfluss zu verarbeiten, also müssen wir sie nur nutzen. Dieses Muster enthält jedoch viel Boilerplate-Code, da wir je nach den verschiedenen Ereignistypen, die wir benötigen, Listener hinzufügen und entfernen könnten. Das funktioniert perfekt auf einer kleinen Webseite, aber sobald die Komplexität und die Funktionen zunehmen, wird es aufgebläht und umständlich zu verwalten, also sind bessere Abstraktionen erforderlich!
Versprechungen sind schwieriger zu beherrschen, lösen aber das Problem der Umkehrung der Kontrolle. Sie sind etwas langsamer als Rückrufe, aber im Gegenzug erhalten wir eine Menge Vertrauenswürdigkeit.
Wir können immer sicher sein, dass ein Promise gelöst oder abgelehnt wird, da es sich um einen Wert handelt, der möglicherweise noch nicht existiert. Promises sind ein vertrauenswürdiger Mechanismus, der auch dabei hilft, asynchronen Code sequentieller auszudrücken. Sie können höchstens einen Auflösungswert haben, was bedeutet, dass ein Promise immer aufgelöst oder abgelehnt werden muss.
So lösen sie die Umkehrung der Kontrolle. Nicht durch das Entfernen von Callbacks, sondern durch die Schaffung eines Mechanismus auf dem Wrapper, der dieses Problem behandelt.
Wir können mehrere Promises in unserem Code verketten, ohne nach jedem einzelnen eine neue Einrückungsebene zu erzwingen, indem wir .then () verwenden.
Versprechen bieten mehr Funktionalität, wie zum Beispiel die Verspreche alles ()
und Promise.race ()
im Vergleich zu den neuesten API-Ergänzungen Promise.allSettled ()
und Promise.any ()
. Bei komplexeren Frontend-Webanwendungen benötigen wir mehr und bessere Mechanismen.
Dies verbessert die Lesbarkeit des Codes und auch die Wartbarkeit des Programms, aber nicht alles ist perfekt. Da sich diese Funktion auf Framework-Ebene befindet, können mehrere Implementierungen je nach Verhalten variieren. Hinzu kommen die Overheadkosten für Zeit und Speicher.
Generatoren wurden in ECMAScript 2015 eingeführt und sind Funktionen, in denen wir den Iterator verwenden und steuern können, was bedeutet, dass Funktionen jederzeit angehalten und wieder aufgenommen werden können. Dies ist ein leistungsstarkes Tool, wenn wir jeden Wert nur dann abrufen möchten, wenn wir ihn benötigen, anstatt alle auf einmal zu erhalten. Dies ist mit der Hinzufügung des Wortes möglich Ausbeute
zu JavaScript.
Wir können in diesem Beispiel sehen, dass für jeden weiter ()
wir erhalten ein Objekt mit dem Wert und einem Flag, das angibt, ob die Generatorfunktionen beendet wurden. Generatoren können aber auch verwendet werden, um asynchrone Abläufe in Konjugationen mit anderen Bibliotheken zu steuern, wie in co oder Redux-Saga, über die ich weiter unten noch mehr sprechen werde.
Schließlich wurde ES2017 eingeführt asynchrone Funktionen macht es viel einfacher, asynchronen Code in JavaScript zu schreiben und zu lesen!
Sie sind viel sauberer als die zuletzt besprochenen Muster, und die Rückgabe einer asynchronen Funktion ist ein Versprechen! Das ist sehr mächtig, weil wir die Güte beider Welten haben. Wie wir bereits besprochen haben, sind Promises die sichere Wahl, wenn es um komplexe asynchrone Operationen geht, aber sie sind nicht so einfach zu lesen und zu beherrschen wie Async/Await-Code.
Ein Nachteil ist, dass es eine benötigt Transpilation Tool, wie Babel, weil Async/Await immer noch syntaktischer Zucker über dem Promises-Code ist.
Da das Ergebnis ein Promise ist und gelöst/abgelehnt werden kann, ist es wichtig, unseren Await-Code in einen Try/Catch einzuschließen. Auf diese Weise können wir Fehler in unserem asynchronen Code richtig behandeln.
Mithilfe von Web-Workern ist es möglich, Skripts und Funktionen in einem anderen Thread auszuführen und Code in asynchronen Hintergrundaufgaben auszuführen. Dies hat keinen Einfluss auf die Benutzerfreundlichkeit der Benutzeroberfläche und kann Daten zwischen Workern und dem Haupt-Thread übertragen.
Der Service Worker in unseren Browsern wird häufig in progressiven Webanwendungen verwendet. Dies besteht darin, einen Webworker für unsere Website zu registrieren und zu entscheiden, welche Dateien zwischengespeichert werden können oder nicht. Dadurch wird die Nutzung der App beschleunigt. Auch wenn der Benutzer offline ist, sind einige Funktionen weiterhin verfügbar. Sie können auch verwendet werden, um umfangreiche Operationen auszuführen, ohne die Benutzeroberfläche oder den JS-Hauptthread einzufrieren.
Mehrere andere Bibliotheken versuchen, diese Probleme zu lösen, wobei jede ihre eigenen Techniken verwendet. Im Folgenden finden Sie einige Beispiele:
Asynchron: Diese Bibliothek eignet sich gut für die Arbeit mit Callbacks, um einige Probleme zu lösen, die in ihnen bestehen, und um das Callback-Höllenproblem zu beseitigen! In den letzten Implementierungen ist es möglich, auch Async/AWAIT-Code zu verwenden.
Bluebird: eine sehr performante Implementierung von Promises, die auch viele zusätzliche Funktionen wie Stornierung, Iteration und Promisify beinhaltet! Letzteres ist ein Wrapper für Funktionen, die mit Callbacks arbeiten, und gibt ein Promise für diese Funktionen zurück.
co: Steuern Sie asynchrone Flüsse mit Generatoren. Diese Bibliothek ist eine Laufzeitumgebung rund um Generatoren. Sie kombiniert das Schlüsselwort yield mit Promises, führt das Generatorergebnis aus und gibt es als Promise-Objekt zurück.
Redux-Saga: Eine Frontend-Bibliothek für den React/Redux-Stack. Dies ist eine Redux-Middleware, die darauf abzielt, die Nebeneffekte von Anwendungen effizienter und einfacher zu handhaben, da sie durch Redux-Aktionen gestartet oder abgebrochen werden können. Diese Implementierung verwendet häufig Generatoren, um Daten über das Internet abzurufen und die erforderlichen Nebeneffekte auf unserer Website anzuwenden.
RxJS: Dies ist ein Muster, das in Angular-Apps verwendet wird, und es ist ein reaktives Muster. Wir erstellen ein Observable, das wir abonnieren können, und warten auf Änderungen, über die wir informiert werden. Mit diesem Muster ist es beispielsweise möglich, Abonnements zu kündigen und Observables zu verketten.
Für einfache Projekte sind Callbacks die einfachste und einfachere Methode, asynchrone Abläufe zu handhaben. Bei größeren Projekten mit einem richtigen Setup würde ich das async/await-Muster wählen, da die Asynchronität leicht zu lesen ist, eine natürliche Fehlerbehandlung hat und es keine Todespyramide gibt.
Das ist die Art von syntaktischem Zucker, den wir für unsere Arbeit benötigen, damit wir ein besser lesbares und wartbares Programm schreiben können.
Wie auf dem obigen Bild zu sehen ist, ist JavaScript zusammen mit seiner lebendigen Community weiterhin die am häufigsten verwendete Sprache auf GitHub.
Dies ist unsere erste Wahl für den Umgang mit asynchronen Abläufen, aber es gibt noch mehr Möglichkeiten, dieselben Ergebnisse zu erzielen, als die in diesem Handbuch beschriebenen. Alles in allem liegt es an Ihnen, zu entscheiden, welches für Ihre Bedürfnisse am besten geeignet ist.
Full-Stack-Entwickler und JavaScript-Liebhaber. Erstklassiges Frontend ist mein Ding, wo ich gerne neue Sachen experimentiere. Kajakfischer, Brauer und Biertrinker!
People who read this post, also found these interesting: