Wenn ich dieses Versprechen aufrufe, stimmt die Ausgabe nicht mit der Reihenfolge der Funktionsaufrufe überein. Das .then
kommt vor dem .catch
, obwohl das Versprechen mit nachgefragt .then
wurde. Was ist der Grund dafür?
const verifier = (a, b) =>
new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false)));
verifier(3, 4)
.then((response) => console.log("response: ", response))
.catch((error) => console.log("error: ", error));
verifier(5, 4)
.then((response) => console.log("response: ", response))
.catch((error) => console.log("error: ", error));
Ausgabe
node promises.js
response: true
error: false
javascript
node.js
Gustavo Alves
quelle
quelle
Antworten:
Dies ist eine coole Frage, um auf den Grund zu gehen.
Wenn Sie dies tun:
verifier(3,4).then(...)
Dadurch wird ein neues Versprechen zurückgegeben, für das ein weiterer Zyklus zur Ereignisschleife erforderlich ist, bevor dieses neu abgelehnte Versprechen den folgenden
.catch()
Handler ausführen kann . Dieser zusätzliche Zyklus ergibt die nächste Sequenz:verifier(5,4).then(...)
Es besteht die Möglichkeit, den
.then()
Handler vor der vorherigen Zeile auszuführen ,.catch()
da er sich bereits in der Warteschlange befand, bevor der.catch()
Handler der ersten Zeile in die Warteschlange gelangt und Elemente in der FIFO-Reihenfolge aus der Warteschlange ausgeführt werden.Beachten Sie, dass das
.then(f1, f2)
Formular , wenn Sie es anstelle von verwenden.then().catch()
, ausgeführt wird, wenn Sie es erwarten, da es kein zusätzliches Versprechen und somit kein zusätzliches Häkchen enthält:const verifier = (a, b) => new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false))); verifier(3, 4) .then((response) => console.log("response (3,4): ", response), (error) => console.log("error (3,4): ", error) ); verifier(5, 4) .then((response) => console.log("response (5,4): ", response)) .catch((error) => console.log("error (5,4): ", error));
Beachten Sie, dass ich auch alle Nachrichten beschriftet habe, damit Sie sehen können, von welchem
verifier()
Anruf sie kommen, was das Lesen der Ausgabe erheblich erleichtert.ES6-Spezifikation zur Bestellung von Rückrufversprechen und ausführlichere Erläuterungen
Die ES6-Spezifikation sagt uns, dass Versprechen "Jobs" (wie es einen Rückruf von einem
.then()
oder aufruft.catch()
) in FIFO-Reihenfolge ausgeführt werden, basierend darauf, wann sie in die Jobwarteschlange eingefügt werden. FIFO wird nicht speziell benannt, es wird jedoch angegeben, dass neue Jobs am Ende der Warteschlange eingefügt werden und Jobs ab dem Anfang der Warteschlange ausgeführt werden. Das implementiert die FIFO-Reihenfolge.PerformPromiseThen (das den Rückruf von ausführt
.then()
) führt zu EnqueueJob. Auf diese Weise wird geplant, dass der Auflösungs- oder Ablehnungshandler tatsächlich ausgeführt wird. EnqueueJob gibt an, dass der ausstehende Job am Ende der Jobwarteschlange hinzugefügt wird. Dann zieht die NextJob- Operation das Element von der Vorderseite der Warteschlange. Dies stellt die FIFO-Reihenfolge bei der Bearbeitung von Jobs aus der Promise-Jobwarteschlange sicher.Im Beispiel in der ursprünglichen Frage erhalten wir die Rückrufe für das
verifier(3,4)
Versprechen und dasverifier(5,4)
Versprechen, die in der Reihenfolge, in der sie ausgeführt wurden, in die Jobwarteschlange eingefügt wurden, da beide ursprünglichen Versprechen erfüllt sind. Wenn der Interpreter dann zur Ereignisschleife zurückkehrt, nimmt er zuerst denverifier(3,4)
Job auf. Dieses Versprechen wird abgelehnt und es gibt keinen Rückruf dafür in derverifier(3,4).then(...)
. Es wird also das zurückgegebene Versprechen abgelehnt, das dazu führtverifier(3,4).then(...)
, dass derverifier(3,4).then(...).catch(...)
Handler in die jobQueue eingefügt wird.Dann kehrt es zur Ereignisschleife zurück und der nächste Job, den es aus der jobQueue abruft, ist der
verifier(5, 4)
Job. Das hat ein gelöstes Versprechen und einen entschlossenen Handler, also nennt es diesen Handler. Dadurch wird dieresponse (5,4):
Ausgabe angezeigt.Dann kehrt es zur Ereignisschleife zurück und der nächste Job, den es aus der jobQueue abruft, ist der
verifier(3,4).then(...).catch(...)
Job, bei dem es ausgeführt wird, und dies verursacht dieerror (3,4)
Ausgabe angezeigt.Dies liegt daran, dass die
.catch()
in der 1. Kette eine Versprechungsstufe tiefer in ihrer Kette liegt als die.then()
in der 2. Kette, die die von Ihnen gemeldete Bestellung verursacht. Dies liegt daran, dass Versprechen-Ketten nicht synchron über die Job-Warteschlange in FIFO-Reihenfolge von einer Ebene zur nächsten durchlaufen werden.Allgemeine Empfehlung, sich auf diese Ebene der Planungsdetails zu verlassen
Zu Ihrer Information, im Allgemeinen versuche ich, Code zu schreiben, der nicht von diesem Grad an detailliertem Timing-Wissen abhängt. Es ist zwar neugierig und gelegentlich nützlich zu verstehen, aber es ist fragiler Code, da eine einfache, scheinbar harmlose Änderung des Codes zu einer Änderung des relativen Timings führen kann. Wenn das Timing zwischen zwei Ketten wie dieser kritisch ist, würde ich den Code lieber so schreiben, dass das Timing so erzwungen wird, wie ich es möchte, anstatt mich auf dieses detaillierte Verständnis zu verlassen.
quelle
.then()
ein neues Versprechen zurückgegeben werden muss, das selbst bei einem zukünftigen Tick asynchron aufgelöst / abgelehnt werden muss, was zu dieser Bestellung führt. Kennen Sie eine Implementierung, bei der die FIFO-Reihenfolge konkurrierender Rückrufe nicht verwendet wird?await
).PerformPromiseThen
Dies führt dazuEnqueueJob
, dass der Auflösungs- oder Ablehnungshandler so aufgerufen wird, dass er aufgerufen wird. EnqueueJob gibt an, dass der ausstehende Job am Ende der Jobwarteschlange hinzugefügt wird. Dann zieht die NextJob- Operation das Element von der Vorderseite der Warteschlange. Dies stellt die FIFO-Reihenfolge in der Promise-Jobwarteschlange sicher.await
in ES11? Ein Link reicht aus. Vielen Dank!!Promise.resolve() .then(() => console.log('a1')) .then(() => console.log('a2')) .then(() => console.log('a3')) Promise.resolve() .then(() => console.log('b1')) .then(() => console.log('b2')) .then(() => console.log('b3'))
Anstelle der Ausgabe a1, a2, a3, b1, b2, b3 sehen Sie aus demselben Grund a1, b1, a2, b2, a3, b3 - jedes Mal wird ein Versprechen zurückgegeben und es geht bis zum Ende der Ereignisschleife Warteschlange. Wir können also dieses "Versprechensrennen" sehen. Das gleiche gilt, wenn es einige verschachtelte Versprechen gibt.
quelle