JS asynchroner Code Unit-Test Magie Promise

JS asynchroner Code Unit-Test Magie Promise

Vorwort

Der Grund für das Schreiben dieses Artikels ist, dass ich beim Schreiben von Unit-Tests die folgenden Tests durchgeführt habe:

neues Versprechen((auflösen, ablehnen) => ablehnen(1)).dann().catch(err => {
    console.log(fehler)
})
asynchrone Funktion jestTest () {
    warte auf Promise.resolve().then()
    console.log('Zu diesem Zeitpunkt wird erwartet, dass der Catch aufgerufen wurde und das Protokoll ausgegeben wird.')
}
jestTest()

Es ist nicht möglich, mit „await“ den Testcode zu blockieren, bis der Catch in der Ereignisschleife aufgerufen wird, wodurch die Ausführung des Catch erkannt und der Test bestanden wird.

Das Wort „Magie“ wird verwendet, weil es im Kettenaufruf von Promsie tatsächlich viele Standardhandler und implizite Werteübertragungen gibt.

Verkettung von Versprechen

Um Ihre Zeit nicht zu verschwenden, schauen wir uns ein Beispiel an:

Versprechen.lösen('Versprechen1')
.then(res => {
    console.log('promise1-1 dann')
})
.then(res => {
    console.log('promise1-2 dann')
})
.then(res => {
    console.log('promise1-3 dann')
})
.then(res => {
    console.log('promise1-4 dann')
})


Versprechen.lösen('versprechen2')
.then(res => {
    console.log('promise2-1 dann')
    wirf einen neuen Fehler (,,Fehler 1 vortäuschen')
})
.then(res => {
    console.log('promise2-2 dann')
    wirf einen neuen Fehler (,,Scheinfehler 2')
})
.catch(err => {
    console.log(fehler)
})

Wenn Ihre Antwort auf die obige Code-Ausgabesequenz mit der folgenden übereinstimmt, können Sie diesen Artikel überspringen:

Versprechen1-1 dann

promise2-1 dann

Versprechen1-2 dann

Versprechen1-3 dann

Fehler: Mock-Fehler 1

Versprechen1-4 dann

Zunächst einmal gibt es eine Prämisse, nämlich, dass Sie bereits wissen, dass die then-Aufrufe dieser beiden Promises kreuzweise gestapelt sind (wie aus den ersten drei Ausgabezeilen ersichtlich). Wenn Sie sich bei diesem Teil nicht sicher sind, können Sie die entsprechenden Artikel zu Event Loop lesen. Gleichzeitig ist zu beachten, dass die Event Loop-Mechanismen von Chrome und Nodejs in den im Artikel angegebenen Versionen bereits identisch sind.

MDN-Fehler

Schauen wir uns die ursprüngliche (von mir geänderte) MDN-Beschreibung von catch an:

Grundsätzlich wird eine Promise-Kette angehalten, wenn eine Ausnahme auftritt, und stattdessen weiter unten in der Kette nach Catch-Handlern gesucht.

Der Kettenaufruf wird beendet, wenn eine Ausnahme auftritt, und die Catch-Anweisung wird zur Ausführung in der Kette gefunden.

Mein anfängliches Missverständnis war das gleiche. Ich dachte fälschlicherweise, dass catch den ersten ausgelösten Fehler direkt abfangen würde, d. h., der Fehler würde nach promise1-2 ausgegeben, d. h., das then, wo promise2-2 steht, würde nicht zum Aufrufstapel hinzugefügt.

Wenn wir jedoch die tatsächlichen Ausgabeergebnisse beobachten, stellen wir fest, dass dies nicht der Fall ist. Dies zeigt, dass die wörtliche Bedeutung der Erklärung von MDN falsch sein sollte. Der Kettenaufruf wurde nicht gestoppt, sondern führte etwas aus, das wir nicht gesehen haben.

Verkettete Standardbehandlung

An dieser Stelle müssen wir die Standardverarbeitung von damals kennen und wir zitieren auch direkt die Beschreibung von MDN:

Wenn das dann aufgerufene Promise einen Zustand (Erfüllung oder Ablehnung) annimmt, für den es keinen Handler gibt, wird ein neues Promise ohne zusätzliche Handler erstellt, das einfach den endgültigen Zustand des ursprünglichen Promise annimmt, für das es dann aufgerufen wurde.

Wenn in Ihrem Promise dann ein Callback zur entsprechenden Zustandsverarbeitung fehlt, wird dann automatisch ein Promise generiert, das den Zustand dieses Promises akzeptiert, d. h., dann wird ein Promise mit derselben Zustandsreferenz zurückgegeben und an nachfolgende Aufrufe übergeben.

Dann ist der zweite Promise-Teil im obigen Code gleichbedeutend mit

Versprechen.lösen('versprechen2')
.then(res => {
    console.log('promise2-1 dann')
    wirf einen neuen Fehler (,,Fehler 1 vortäuschen')
})
.then(res => {
    console.log('promise2-2 dann')
    wirf einen neuen Fehler (,,Scheinfehler 2')
// Beachten Sie dies bei Ablehnung
}, (err) => {
    returniere Promise.reject(err)
})
.catch(err => {
    console.log(fehler)
})

Das heißt, das „then“ von promise2-2 wird zwischen promise1-2 und promise1-3 der Ausgabeergebnisse ausgeführt, was bedeutet, dass der Kettenaufruf nicht direkt gestoppt wird und das „then“ von promise2-2 trotzdem zum Aufrufstapel hinzugefügt wird. Der Haken ist nicht der vom ersten „Dann“ geworfene Fehler, der direkt abgefangen wird, sondern das Versprechen desselben Status, der vom versteckten „onRejected“ zurückgegeben wird.

Abkürzung

Ebenso müssen wir wissen, dass catch(onRejected) eine Abkürzung von then(undefined, onRejected) ist, d. h., selbst wenn im vorherigen Aufruf der Aufrufkette kein Fehler vorliegt, wird catch in den Aufrufstapel eingegeben, anstatt ihn direkt zu überspringen.

Versprechen.lösen('Versprechen1')
.then(res => {
    console.log('promise1-1 dann')
})
.then(res => {
    console.log('promise1-2 dann')
})
.then(res => {
    console.log('promise1-3 dann')
})


Versprechen.lösen('versprechen2')
.then(res => {
    console.log('promise2-1 dann')
})
.catch(err => {
    console.log(fehler)
})
.then(res => {
    console.log('Eigentlich bin ich dann promise2-3')
})

asynchron warten

Als Erstes ist zu beachten, dass in den im Artikel angegebenen NodeJs- und Chrome-Versionen f(await promise) vollständig gleichwertig mit promise.then(f) ist.

Natürlich dürfen wir bei der Diskussion von Promises das asynchrone Warten nicht außer Acht lassen. Obwohl die Verarbeitungslogik der beiden gleich ist, wenn der Promise-Status onResolve ist, ist die Ausführungslogik der Fehlerbehandlung unterschiedlich. Wenn beim asynchronen Warten ein Fehler auftritt, wird die Ausführung des nachfolgenden Wartens tatsächlich direkt übersprungen.

const promiseReject = neues Promise((auflösen, ablehnen) => {
    ablehnen(neuer Fehler('Fehler'))
})
const promiseResolve1 = neues Promise((lösen, ablehnen) => {
    lösen('korrigieren')
})
const promiseResolve2 = neues Versprechen((lösen, ablehnen) => {
    lösen('korrigieren')
})
const promiseResolve3 = neues Versprechen((lösen, ablehnen) => {
    lösen('korrigieren')
})
Funktion demo1 () {
    VersprechenAblehnen
    .then(() => {
        konsole.log('1-1')
    })
    .catch(err => {
        konsole.log('1-2')
    })
}

asynchrone Funktion demo2 () {
    versuchen {
        abwarten VersprechenAblehnen
        warte auf promiseResolve1
        warte auf promiseResolve2
        warte auf promiseResolve3
    } Fehler abfangen {
        konsole.log('2-1')
    }
}
// 2-1
// 1-2

Oben sind die Details des magischen Versprechens des asynchronen Code-Unittests von JS aufgeführt. Weitere Informationen zum Versprechen des asynchronen Codes von JS finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • js Promise-Methode zur gleichzeitigen Steuerung
  • JavaScript verwendet Promise zur Verarbeitung mehrerer wiederholter Anfragen
  • So verwenden Sie Promise in JavaScript, um die Anzahl gleichzeitiger Anfragen zu steuern
  • Fragen zum Vorstellungsgespräch zu JS 9 Promise
  • So fügen Sie in JS eine Abbruchfunktion zu einem Versprechen hinzu
  • JS Asynchronous Stack Tracing: Warum „await“ besser ist als „Promise“
  • Asynchrone Programmierung in Javascript: Verstehen Sie Promise wirklich?
  • Detaillierte Erklärung von JavaScript Promise und Async/Await
  • Front-End-JavaScript-Versprechen

<<:  Lösung für die Fehlermeldung "java.sql.SQLException: Incorrect string value:'\xF0\x9F\x92\xA9\x0D\x0A...'" beim Speichern von Emoticons in MySQL

>>:  Detaillierte Erläuterung der Schritte zur Konfiguration des Centos7-Bridge-Netzwerks unter VMware

Artikel empfehlen

Detaillierte Erklärung der GaussDB zur MySQL-Leistungsoptimierung

Inhaltsverzeichnis Hintergrund Inspiration kommt ...

Analyse des SELECT-Abfrageausdrucks in der MySQL-Datenbank

Ein großer Teil der Datenverwaltung besteht aus S...

Detaillierte Erklärung zum effizienten MySQL-Paging

Vorwort Normalerweise wird für MySQL-Abfragen mit...

Detaillierte Erklärung zum Anzeigen und Einstellen des SQL-Modus in MySQL

Anzeigen und Einstellen des SQL-Modus in MySQL My...

So verwenden Sie vue3+TypeScript+vue-router

Inhaltsverzeichnis Einfach zu bedienen Erstellen ...

Schritte zum Installieren von Superset unter dem Win10-System

Superset ist ein leichtes Self-Service-BI-Framewo...

Implementierung des Whack-a-Mole-Spiels in JavaScript

In diesem Artikel finden Sie den spezifischen Cod...

js implementiert Tabellen-Drag-Optionen

In diesem Artikelbeispiel wird der spezifische JS...

So lösen Sie das Phantomleseproblem in MySQL

Inhaltsverzeichnis Vorwort 1. Was ist Phantomlese...

So stellen Sie Gitlab mit Docker-Compose bereit

Docker-Compose stellt Gitlab bereit 1. Docker ins...

So erstellen Sie mit Photoshop ein Web-Drahtgittermodell

Dieser Beitrag stellt eine Reihe kostenloser Phot...