Schlüsselpunkte
Dieser Artikel wurde ursprünglich in Codebrahma veröffentlicht.
JavaScript ist eine Programmiersprache mit einem Thread. Das heißt, wenn Sie den folgenden Code schreiben ...
… Die zweite Zeile wird erst nach Ausführung der ersten Zeile ausgeführt. Dies ist in den meisten Fällen kein Problem, da der Client oder Server Millionen von Berechnungen pro Sekunde ausführt. Wir bemerken diese Effekte nur, wenn wir kostspielige Berechnungen durchführen (eine Aufgabe, die eine Weile dauert, um abgeschlossen zu werden -, dauert eine Netzwerkanforderung einige Zeit, um zurückzukehren).
Warum zeige ich hier nur API -Anrufe (Netzwerkanforderungen)? Was ist mit anderen asynchronen Operationen? API -Aufrufe sind ein sehr einfaches und nützliches Beispiel, um zu beschreiben, wie mit asynchronen Operationen umgegangen werden. Es gibt andere Vorgänge, wie setTimeout()
, leistungsintensives Computer, Bildbelastung und event-gesteuerte Operationen.
Beim Erstellen einer Anwendung müssen wir überlegen, wie sich die asynchrone Ausführung auf die Struktur auswirkt. Stellen Sie sich beispielsweise fetch()
als eine Funktion vor, die einen API -Aufruf (Netzwerkanforderung) aus dem Browser ausführt. (Ignorieren Sie, ob es sich um eine AJAX -Anfrage handelt. Behandle ihr Verhalten einfach als asynchron oder synchron.) Die Zeit, die zu verstrichen ist, wenn die Anforderung auf dem Server verarbeitet wird, tritt nicht auf dem Haupt -Thread auf. Daher wird Ihr JS -Code weiter ausgeführt und sobald die Anforderung eine Antwort zurückgibt, aktualisiert er den Thread.
Betrachten Sie diesen Code:
userId = fetch(userEndPoint); // 从 userEndpoint 获取 userId userDetails = fetch(userEndpoint, userId) // 为此特定 userId 获取数据。
In diesem Fall, da fetch()
asynchron ist, werden wir, wenn wir versuchen, userDetails
zu erhalten, nicht userId
. Wir müssen es also so erstellen, dass die zweite Zeile erst nach der Rückgabe der ersten Zeile die Antwort ausgeführt wird.
Die meisten modernen Implementierungen für Netzwerkanforderungen sind asynchron. Dies funktioniert jedoch nicht immer, da wir uns auf frühere API -Antwortdaten für nachfolgende API -Aufrufe verlassen. Lassen Sie uns sehen, wie Sie es speziell in einer ReactJS/Redux -Anwendung erstellen.
React ist eine Front-End-Bibliothek zum Erstellen von Benutzeroberflächen. Redux ist ein staatlicher Container, der den gesamten Zustand einer Anwendung verwaltet. Durch die Verwendung von React mit Redux können wir effiziente und skalierbare Anwendungen erstellen. In einer solchen Reaktionsanwendung gibt es verschiedene Möglichkeiten, asynchrone Operationen aufzubauen. Für jede Methode werden wir ihre Vor- und Nachteile in Bezug auf die folgenden Faktoren erörtern:
Für jede Methode werden wir diese beiden API -Aufrufe ausführen:
userDetails
Angenommen, der Endpunkt ist . Es wird die Stadt in die Antwort einbeziehen. Die Antwort ist ein Objekt:
2.
/details
Angenommen, der Endpunkt ist
userId = fetch(userEndPoint); // 从 userEndpoint 获取 userId userDetails = fetch(userEndpoint, userId) // 为此特定 userId 获取数据。
/restuarants/:city
Verwenden von Redux Thunk
userDetails: { … city: 'city', … };
Verwenden von Redux Observables
setState
Ich habe die obigen Methoden ausdrücklich ausgewählt, da sie die am häufigsten verwendeten Methoden in großen Projekten sind. Es gibt noch andere Methoden, die für eine bestimmte Aufgabe spezifischer sind und nicht alle Funktionen haben, die von einer komplexen Anwendung erforderlich sind (z. B. In unserem Beispiel werden wir die Axios -Bibliothek verwenden, um die Daten zu erhalten, was ein Versprechen zurückgibt, wenn wir eine Netzwerkanforderung stellen. Das Versprechen kann eine Antwort analysieren und zurückgeben oder einen Fehler machen. Sobald die React -Komponente
montiert ist, können wir es direkt wie folgt bekommen:Auf diese Weise wird die-Komponente
die Restaurantliste automatisch neu rendern und lädt die Restaurantliste automatisch erneut.
async/act ist eine neue Implementierung, mit der wir asynchrone Operationen ausführen können. Zum Beispiel kann die gleiche Funktion erreicht werden durch:
Beide Methoden sind am einfachsten. Da sich die gesamte Logik in der Komponente befindet, können wir nach dem Laden der Komponente problemlos alle Daten gleichzeitig abrufen.['restaurant1', 'restaurant2', …]
Nachteile dieser Methode Das Problem tritt auf, wenn komplexe datenbasierte Interaktionen auftreten. Betrachten Sie beispielsweise die folgende Situation:
Statusverwaltung mit globalem Speicher kann in diesen Fällen die Hälfte unserer Probleme lösen. Wir werden Redux als unseren globalen Speicher verwenden.
Geschäftslogik an den richtigen Ort verschieben, wenn wir in Betracht ziehen, die Geschäftslogik aus der Komponente herauszuholen, wo genau können wir das tun? In Aktionen? In Reduzierern? Durch Middleware? Die Architektur von Redux ist synchron. Sobald Sie eine Aktion (JS -Objekt) verteilen und den Speicher erreicht haben, arbeitet der Reduzierer darauf.
Stellen Sie sicher
verteilen, und wenn es fertig ist, können wir dispatch({ type: 'FETCH_STARTED' })
verteilen. dispatch({ type: 'FETCH_SUCCESS' })
Verwenden von Redux Thunk
und dispatch
als Parameter der Funktion bereitgestellt wird. Wir verwenden getState
, um die erforderlichen Aktionen zum richtigen Zeitpunkt zu verteilen. Die Vorteile sind: dispatch
userId = fetch(userEndPoint); // 从 userEndpoint 获取 userId userDetails = fetch(userEndpoint, userId) // 为此特定 userId 获取数据。
Wie Sie sehen, haben wir jetzt eine gute Kontrolle darüber, welche Art von Aktion verteilt ist. Jeder Funktionsaufruf (z. B. fetchStarted()
, fetchUserDetailsSuccess()
, fetchRestaurantsSuccess()
und fetchError()
) verteilen eine Aktion vom Typ Normales JavaScript -Objekt vom Typ, und bei Bedarf können zusätzliche Details hinzugefügt werden. Jetzt besteht die Aufgabe des Reduzierers darin, jede Aktion zu verarbeiten und die Ansicht zu aktualisieren. Ich habe nicht über Reduzierer gesprochen, weil es von hier aus einfach ist und die Implementierung möglicherweise anders sein kann.
Um diese Funktion zu erledigen, müssen wir die React -Komponente an die Redux anschließen und die Aktion mit der Redux -Bibliothek an die Komponente binden. Sobald wir fertig sind, können wir einfach this.props.getRestaurants()
aufrufen, was wiederum alle oben genannten Aufgaben behandelt und die Ansicht gemäß dem Reduzierer aktualisieren.
Für seine Skalierbarkeit kann Redux Thunk für Anwendungen verwendet werden, die keine komplexe Kontrolle asynchroner Aktionen beinhalten. Darüber hinaus funktioniert es nahtlos mit anderen Bibliotheken, wie im folgenden Abschnitt beschrieben.
Es ist jedoch immer noch ein bisschen schwierig, bestimmte Aufgaben mit Redux Thunk auszuführen. Zum Beispiel müssen wir den Zwischenabrufvorgang innehalten oder nur die neuesten Anrufe zulassen, wenn mehrere solche Anrufe vorhanden sind oder wenn andere APIs diese Daten erhalten und wir abbrechen müssen.
Wir können diese immer noch implementieren, aber es wird komplizierter sein, genau auszuführen. Im Vergleich zu anderen Bibliotheken wird die Code -Klarheit komplexer Aufgaben etwas schlechter sein und schwieriger zu pflegen.
Mit der Redux-Saga-Middleware können wir den zusätzlichen Vorteil erzielen, um die meisten der oben genannten Funktionen zu beheben. Redux-Saga wird basierend auf dem ES6-Generator entwickelt.
Redux-Saga bietet eine API, die die folgenden Ziele erreicht:
Saga verwendet eine Kombination aus ES6 -Generator und Async/Awit API, um asynchrone Operationen zu vereinfachen. Grundsätzlich arbeitet es an seinen separaten Threads, wo wir mehrere API -Anrufe tätigen können. Wir können ihre API verwenden, um jeden Anruf synchron oder asynchron zu gestalten, abhängig vom Anwendungsfall. Die API bietet die Möglichkeit, einen Thread auf derselben Zeile warten zu lassen, bis die Anforderung eine Antwort zurückgibt. Abgesehen davon bietet diese Bibliothek viele andere APIs, die API -Anfragen sehr einfach zu handhaben.
Betrachten Sie unser vorheriges Beispiel: Wenn wir eine Saga initialisieren und mit Redux basierend auf dem konfigurieren, was in ihrer Dokumentation erwähnt wird, können wir Folgendes tun:
userDetails: { … city: 'city', … };
Wenn wir es also mit einer einfachen Aktion vom Typ FETCH_RESTAURANTS
verteilen, hört die Saga Middleware an und reagiert. Tatsächlich wird keine Aktion von Middleware verwendet. Es hört nur noch einige andere Aufgaben aus und verteilt bei Bedarf neue Aktionen. Durch die Verwendung dieser Architektur können wir mehrere Anforderungen verteilen, von denen jede beschreibt:
und so weiter.
Zusätzlich können Sie die Vorteile von fetchRestaurantSaga()
sehen. Wir verwenden derzeit die call
API, um Blockierungsanrufe zu implementieren. SAGA liefert andere APIs wie fork()
, die nicht blockierende Anrufe implementiert. Wir können Blockier- und nicht blockierende Anrufe kombinieren, um eine Struktur aufrechtzuerhalten, die für unsere Anwendung geeignet ist.
Mit Skalierbarkeit ist die Verwendung von SAGA von Vorteil:
Wie in seiner Dokumentation angegeben, ist "epic der Kernprimitive des Redux-beobachtbaren Abschnitts:
Für unsere Aufgabe können wir einfach den folgenden Code schreiben:
userId = fetch(userEndPoint); // 从 userEndpoint 获取 userId userDetails = fetch(userEndpoint, userId) // 为此特定 userId 获取数据。
Zuerst mag dies ein bisschen verwirrend erscheinen. Je mehr Sie RXJs verstehen, desto einfacher ist es, ein Epos zu erstellen.
Wie Saga können wir mehrere Aktionen verteilen, von denen jeder beschreibt, in welchem Teil der API -Anforderungskette sich der Thread derzeit befindet.
In Bezug auf die Skalierbarkeit können wir Epic basierend auf einer bestimmten Aufgabe teilen oder kombinieren. Daher kann diese Bibliothek dazu beitragen, skalierbare Anwendungen aufzubauen. Wenn wir das beobachtbare Muster des Schreibens des Codes verstehen, ist die Code -Klarheit gut.
Wie kann ich bestimmen, welche Bibliothek verwendet werden soll? Es hängt davon ab, wie komplex unsere API -Anfragen sind.
Wie wählen Sie zwischen Redux-Saga und Redux-beobachtbar? Es hängt vom Lerngenerator oder RXJs ab. Beide sind unterschiedliche Konzepte, aber ebenso gut genug. Ich schlage vor, beide zu sehen, welche für Sie besser ist.
Wo ist die Geschäftslogik für die Verarbeitung von APIs? Es ist am besten, es vor den Reduzierer zu stellen, aber nicht in der Komponente. Der beste Weg ist in der Middleware (mit Saga oder Observable).
Sie können mehr React -Entwicklungsartikel bei Codebrahma lesen.
Middleware in Redux spielt eine entscheidende Rolle beim Umgang mit asynchronen Operationen. Es bietet einen Erweiterungspunkt von Drittanbietern zwischen der Verteilungsaktion und der Aktion am Reduzierer. Middleware kann verwendet werden, um Aktionen aufzuzeichnen, zu ändern und sogar zu stornieren sowie andere Aktionen zu verteilen. Im Kontext asynchroner Vorgänge ermöglicht Middleware wie Redux Thunk oder Redux -Saga die Aktion Ersteller, die Funktionen anstelle von Aktionen zurückgeben. Diese Funktion kann dann verwendet werden, um die Verteilung einer Aktion zu verzögern oder nur eine Aktion zu verteilen, wenn ein bestimmter Zustand erfüllt ist.
Redux Thunk ist eine Middleware, mit der Sie Action -Ersteller schreiben können, die Funktionen anstelle von Action zurückgeben. Thunk kann verwendet werden, um die Verteilung von Aktionen zu verzögern oder Aktionen zu verteilen, wenn bestimmte Bedingungen erfüllt sind. Diese Funktion macht es zu einem hervorragenden Werkzeug für den Umgang mit asynchronen Operationen in Redux. Sie können beispielsweise eine Aktion verteilen, um den Beginn eines API -Aufrufs anzuzeigen und dann eine andere Aktion zu verteilen, wenn der Anruf Daten oder Fehlermeldungen zurückgibt.
Redux Thunk und Redux -Saga sind beide Middleware, um Nebenwirkungen in Redux zu verwalten, einschließlich asynchroner Operationen. Der Hauptunterschied zwischen beiden ist ihr Ansatz. Redux Thunk verwendet Callback -Funktionen, um asynchrone Operationen zu verarbeiten, während Redux -Saga Generatorfunktionen und deklarative Methoden verwendet. Dies macht Redux -Saga leistungsfähiger und flexibler, aber auch komplexer. Wenn Ihre Anwendung einfache asynchrone Operationen hat, kann Redux Thunk ausreichen. Für komplexere Szenarien, die Rassenbedingungen, Stornierung und IF-ELSE-Logik beinhalten, ist Redux-Saga jedoch eine bessere Wahl.
Aktion kann verteilt werden, wenn während einer asynchronen Operation ein Fehler auftritt, um die Fehlerbehandlung bei asynchronem Betrieb in Redux zu verarbeiten. Diese Aktion kann ihre Fehlermeldung als Nutzlast aufnehmen. Sie können diese Aktion dann im Reduzierer umgehen, um den Status mit der Fehlermeldung zu aktualisieren. Auf diese Weise kann eine Fehlermeldung an den Benutzer angezeigt oder zum Debuggen aufgezeichnet werden.
asynchrone Aktionen in Redux können getestet werden, indem Redux -Speicher- und API -Aufrufe verspottet werden. Für den Redux -Speicher können Sie Bibliotheken wie redux-mock-store
verwenden. Für API -Aufrufe können Sie Bibliotheken wie fetch-mock
oder nock
verwenden. In Ihren Tests können Sie eine asynchrone Aktion verteilen und dann behaupten, dass die erwartete Aktion mit der richtigen Nutzlast verteilt wurde.
Middleware wie Redux -Saga kann verwendet werden, um asynchrone Vorgänge in Redux abzubrechen. Redux Saga verwendet Generatorfunktionen, die mit cancel
Effekt abgebrochen werden können. Wenn der Effekt cancel
Effekt erfolgt, wird die Saga von seinem Startpunkt abgebrochen, bis der aktuelle Effekt aufgehoben ist.
Middleware wie Redux -Saga kann verwendet werden, um die Rennbedingungen in asynchronen Operationen in Redux zu bewältigen. Redux -Saga liefert Effekte wie takeLatest
und takeEvery
, mit denen gleichzeitige Aktionen verarbeitet werden können. Wenn beispielsweise die zuvor gestartete Saga -Aufgabe noch ausgeführt wird, wenn eine neue Aktion verteilt wird, storniert takeLatest
die Aufgabe.
Redux Thunk unterstützt nativ asynchron/wartet. In Ihrem Action -Schöpfer können Sie asynchrone Funktionen anstelle von regulären Funktionen zurückgeben. In dieser asynchronen Funktion können Sie Async/Auseit verwenden, um asynchrone Operationen zu verarbeiten. Wenn der asynchrone Vorgang abgeschlossen ist, kann die Funktion dispatch
mit dem Aktionsobjekt aufgerufen werden.
Der Ladestatus in asynchronen Operationen in Redux kann durch Verteilung von Aktionen vor und nach asynchronen Operationen behandelt werden. Die vor dem Vorgang verteilte Aktion kann den Laststatus auf true festlegen und die nach dem Vorgang verteilte Aktion auf false festlegen. In Ihrem Reduzierer können Sie diese Aktionen erledigen, um den Lastzustand im Speicher zu aktualisieren.
Nebenwirkungen in Redux können mit Middleware wie Redux Thunk oder Redux -Saga behandelt werden. Mit dieser Middleware können Sie Action -Ersteller schreiben, die Funktionen anstelle von Aktionen zurückgeben. Diese Funktion kann verwendet werden, um Nebenwirkungen wie asynchrone Operationen, Protokollierung und konditionell verteilte Aktionen durchzuführen.
Das obige ist der detaillierte Inhalt vonAsynchronen Operationen in React Redux -Anwendungen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!