Perfekte Lösung für asynchrone Timeout-Vorgänge im JavaScript-Frontend

Perfekte Lösung für asynchrone Timeout-Vorgänge im JavaScript-Frontend

Seit der Veröffentlichung der Funktionen Promise ES2015 und async/await ES2017 von ECMAScript ist Asynchronie in der Front-End-Welt zu einer besonders häufigen Operation geworden. Es gibt einige Unterschiede in der Reihenfolge, in der asynchroner und synchroner Code Probleme verarbeiten. Das Schreiben von asynchronem Code erfordert ein anderes „Bewusstsein“ als das Schreiben von synchronem Code.

Was passiert, wenn die Ausführung eines Codes lange dauert?

Handelt es sich um synchronen Code, kommt es zu einem Phänomen namens „Nichtreagieren“ oder, um es in Laiensprache auszudrücken, „Tod“. Was aber, wenn es sich um asynchronen Code handelt? Möglicherweise erhalten wir das Ergebnis nicht, aber anderer Code wird fortgesetzt, als wäre nichts passiert.

Natürlich ist es nicht so, dass die Sache nicht wirklich passiert wäre, es treten nur unter unterschiedlichen Umständen unterschiedliche Phänomene auf. Beispielsweise sieht eine Seite mit einer Ladeanimation so aus, als würde sie ständig geladen. Ein anderes Beispiel ist eine Seite, die Daten aktualisieren sollte, bei der Sie die Datenänderung jedoch nicht sehen können.

Beispielsweise kann ein Dialogfeld auf keinen Fall geschlossen werden ... Dieses Phänomen wird von uns als BUGs bezeichnet. Es gibt aber auch Fälle, in denen ein asynchroner Vorgang kein „Echo“ ausgibt und stillschweigend beendet wird. Niemand weiß davon, und nach dem Aktualisieren der Seite bleibt nicht einmal eine Spur davon übrig.

Axios verfügt über eine Timeout-Behandlung

Die Verwendung von Axios zum Tätigen von Web-API-Aufrufen ist ein gängiger asynchroner Betriebsvorgang. Normalerweise wird unser Code folgendermaßen geschrieben:

versuchen {
    const res = warte auf axios.get(URL, Optionen);
    //TODO, fahren Sie mit den nachfolgenden Aufgaben wie gewohnt fort} catch(err) {
    // TODO: Fehlertoleranz durchführen oder einen Fehler melden}

Dieser Code funktioniert normalerweise gut, bis sich eines Tages ein Benutzer beschwert: Warum erfolgt nach so langer Wartezeit keine Antwort?

Dann erkannte der Entwickler, dass es aufgrund der erhöhten Belastung des Servers schwierig war, sofort auf diese Anfrage zu reagieren. Unter Berücksichtigung der Gefühle des Benutzers wird eine Ladeanimation hinzugefügt:

versuchen {
    zeigeLaden();
    const res = warte auf axios.get(URL, Optionen);
    //TODO normales Geschäft} catch (err) {
    //TODO Fehlertoleranzverarbeitung} finally {
    ausblendenLaden();
}

Eines Tages sagte jedoch ein Benutzer: „Ich habe eine halbe Stunde gewartet, aber es drehte sich einfach immer weiter im Kreis!“ Der Entwickler erkannte also, dass die Anfrage aus irgendeinem Grund hängen geblieben war. In diesem Fall sollte die Anfrage erneut gesendet oder direkt an den Benutzer gemeldet werden – oder es sollte eine Timeout-Prüfung hinzugefügt werden.

Glücklicherweise kann Axios mit Timeouts umgehen. Fügen Sie einfach ein timeout: 3000 in options hinzu, um das Problem zu lösen. Wenn ein Timeout auftritt, können Sie es im catch -Block erkennen und behandeln:

versuchen {...}
fangen (Fehler) {
    wenn (err.isAxiosError && !err.response && err.request
        && err.message.startsWith("Zeitüberschreitung")) {
        // Wenn die Axios-Anfrage falsch ist und es sich bei der Nachricht um eine verzögerte Nachricht handelt, // behandelt TODO das Timeout}
}
Endlich {...}

Axios ist in Ordnung, aber was ist, wenn wir fetch() verwenden?

Umgang mit fetch()-Timeouts

fetch() selbst kann keine Timeouts verarbeiten, daher müssen wir das Timeout ermitteln und AbortController verwenden, um die Anforderungsoperation „Abbrechen“ auszulösen.

Wenn Sie einen fetch() Vorgang abbrechen müssen, holen Sie einfach signal von einem AbortController -Objekt und übergeben Sie das Signalobjekt als Option fetch() . Wahrscheinlich ist es so:

const ac = neuer AbortController();
const { signal } = ac;
holen(URL, {Signal}).dann(res => {
    //TODO Geschäftliches erledigen});
 
// Den Abrufvorgang nach 1 Sekunde abbrechen. setTimeout(() => ac.abort(), 1000);

ac.abort() sendet ein Signal an signal , löst dessen abort aus und setzt dessen Eigenschaft .aborted auf true . fetch() -Verarbeitung verwendet diese Informationen, um die Anforderung abzubrechen.

Das obige Beispiel zeigt, wie die Timeout-Behandlung für fetch() Operationen implementiert wird. Wenn Sie zur Verarbeitung await verwenden, müssen Sie setTimeout(...) vor fetch(...) setzen:

const ac = neuer AbortController();
const { signal } = ac;
setTimeout(() => ac.abort(), 1000);
const res = warte auf fetch(url, { signal }).catch(() => undefiniert);

Um die Verwendung try ... catch ... zur Behandlung von Anforderungsfehlern zu vermeiden, wird nach fetch() ein .catch(...) hinzugefügt, um Fehler zu ignorieren. Wenn ein Fehler auftritt, wird res der Wert undefined zugewiesen. Für die tatsächliche Geschäftsabwicklung ist möglicherweise eine angemessenere catch() Verarbeitung erforderlich, damit res identifizierbare Fehlerinformationen enthalten können.

Wir hätten hier aufhören können, aber das Schreiben eines so langen Codestücks für jeden fetch() -Aufruf wäre mühsam, also kapseln wir es zusammen:

asynchrone Funktion fetchWithTimeout(timeout, resoure, init = {}) {
    const ac = neuer AbortController();
    konstantes Signal = Wechselstromsignal;
    setTimeout(() => ac.abort(), Zeitüberschreitung);
    returniere fetch(Ressource, { ...init, Signal });
}

Ist das ok? Nein, es gibt ein Problem.

Wenn wir im setTimeout(...) des obigen Codes eine Nachricht ausgeben:

setzeTimeout(() => {
    console.log("Es ist eine Zeitüberschreitung");
    ac.abort();
}, Zeitüberschreitung);

Und geben Sie dem Anruf ausreichend Zeit:

fetchWithTimeout(5000, url).then(res => console.log("Erfolg"));

Wir sehen die Ausgabe success und nach 5 Sekunden die Ausgabe It's timeout .

Übrigens: Obwohl wir das Timeout für fetch(...) behandelt haben, haben wir timer nicht beendet, als fetch(...) erfolgreich war. Wie konnte einem aufmerksamen Programmierer ein solcher Fehler unterlaufen? Töte ihn!

asynchrone Funktion fetchWithTimeout(timeout, resoure, init = {}) {
    const ac = neuer AbortController();
    konstantes Signal = Wechselstromsignal;    
    const timer = setTimeout(() => {
        console.log("Es ist eine Zeitüberschreitung");
        return ac.abort();
    }, Zeitüberschreitung);    
    versuchen {
        returniere „warte auf Abruf“ (Ressource, { ...init, Signal });
    Endlich
        Zeitüberschreitung löschen(Timer);
    }
}

Perfekt! Aber das Problem ist noch nicht gelöst.

Bei allem kann es zu einer Zeitüberschreitung kommen

Sowohl Axios als auch Fetch bieten Möglichkeiten, asynchrone Vorgänge zu unterbrechen, aber was ist mit einem normalen Promise, das nicht über abort Abbruchfunktion verfügt?

Zu einem solchen Versprechen kann ich nur sagen: Lasst ihn gehen, lasst ihn es bis ans Ende aller Zeiten tun – ich kann ihn sowieso nicht aufhalten. Aber das Leben muss weitergehen, ich kann nicht länger warten!

In diesem Fall können wir setTimeout() in ein Promise einbinden und dann Promise.race() verwenden, um „kein Warten nach Ablauf der Zeit“ zu implementieren:

Rennen bedeutet Rennen, also ist das Verhalten von Promise.race() leicht zu verstehen, oder?

Funktion warteMitTimeout(Versprechen, Timeout, TimeoutMessage = "Timeout") {
    lass den Timer;
    const timeoutPromise = neues Versprechen((_, ablehnen) => {
        Timer = Timeout festlegen(() => ablehnen(Timeout-Nachricht), Zeitüberschreitung);
    }); 
    returniere Promise.race([timeoutPromise, Versprechen])
        .finally(() => clearTimeout(timer)); // Vergessen Sie nicht, den Timer zu löschen
}

Sie können ein Timeout schreiben, um den Effekt zu simulieren:

(asynchron () => {
    const business = neues Versprechen(auflösen => setTimeout(auflösen, 1000 * 10));
    versuchen {
        warte auf waitWithTimeout(business, 1000);
        console.log("[Erfolg]");
    } fangen (Fehler) {
        console.log("[Fehler]", err); // [Fehler] Zeitüberschreitung
    }
})();

Oben finden Sie ausführliche Informationen zur perfekten Lösung für asynchrone Front-End-Timeout-Operationen in JavaScript. Weitere Informationen zur Lösung asynchroner Front-End-Timeout-Operationen finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Zusammenfassung mehrerer gängiger Verarbeitungsmethoden für asynchrone JavaScript-Operationen
  • Drei Lösungen für das asynchrone Laden von js
  • Eine kurze Erläuterung zum ordnungsgemäßen Umgang mit asynchronen JavaScript-Fehlern
  • Lernen Sie von mir JavaScript, um Ausnahmen bei der asynchronen Programmierung zu lösen
  • Korrekte Handhabung des Vue Axios-Anforderungstimeouts

<<:  So ändern Sie die Standardübermittlungsmethode des Formulars

>>:  Beispielcode zur Implementierung einer Hohlmaskenebene mit CSS

Artikel empfehlen

Einige etwas komplexere Verwendungsbeispielcodes in MySQL

Vorwort Ich glaube, dass die Syntax von MySQL nic...

Lassen Sie uns über Parameter in MySQL sprechen

Vorwort: In einigen früheren Artikeln haben wir h...

So verwenden Sie wangEditor in Vue und erhalten durch Echo von Daten den Fokus

Bei der Hintergrundverwaltung von Projekten werde...

Detaillierte Erklärung der Verwendung des Fuser-Befehls in Linux

beschreiben: fuser kann anzeigen, welches Program...

Allgemeine Struktur-Tags in XHTML

Struktur Text, Kopf, HTML, Titel Text abbr, Akron...

20 hervorragende Beispiele für die Farbabstimmung auf ausländischen Webseiten

In diesem Artikel werden 20 hervorragende Beispiel...

JavaScript zum Erzielen eines Mauszieheffekts

In diesem Artikel wird der spezifische JavaScript...

CentOS7 64-Bit-Installation MySQL Grafik-Tutorial

Voraussetzungen für die Installation von MySQL: I...

Detaillierte Erläuterung des Mysql-Kommunikationsprotokolls

1.Mysql-Verbindungsmethode Um das MySQL-Kommunika...

So beheben Sie den abnormalen Start von mysql5.7.21

Ein Kollege meldete, dass eine MySQL-Instanz aufg...

Vue implementiert das Hinzufügen von Wasserzeichen zu hochgeladenen Bildern

In diesem Artikel wird der spezifische Implementi...