Gibt es bei den folgenden Codebeispielen Unterschiede im Verhalten, und wenn ja, welche Unterschiede gibt es?
return await promise
async function delay1Second() {
return (await delay(1000));
}
return promise
async function delay1Second() {
return delay(1000);
}
So wie ich es verstehe, würde der erste eine Fehlerbehandlung innerhalb der asynchronen Funktion haben, und Fehler würden aus dem Versprechen der asynchronen Funktion heraussprudeln. Die zweite würde jedoch einen Tick weniger erfordern. Ist das richtig?
Dieses Snippet ist nur eine übliche Funktion, um ein Versprechen als Referenz zurückzugeben.
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
javascript
async-await
PitaJ
quelle
quelle
async
aus Ihrem zweiten (return promise
) Beispiel entfernen .promise.then(() => nestedPromise)
würde sich abflachen und dem "folgen"nestedPromise
. Interessant, wie es sich von verschachtelten Aufgaben in C # unterscheidet, bei denen wir es tun müsstenUnwrap
. Nebenbei bemerkt, es scheint, dassawait somePromise
AufrufePromise.resolve(somePromise).then
nicht nursomePromise.then
mit einigen interessanten semantischen Unterschieden.Antworten:
Meistens gibt es keinen beobachtbaren Unterschied zwischen
return
undreturn await
. Beide Versionen vondelay1Second
haben genau das gleiche beobachtbare Verhalten (abhängig von der Implementierung verwendet diereturn await
Version jedoch möglicherweise etwas mehr Speicher, daPromise
möglicherweise ein Zwischenobjekt erstellt wird).Doch wie @PitaJ darauf hingewiesen, gibt es einen Fall , in dem es ein Unterschied ist: Wenn die
return
oderreturn await
in einem verschachtelt isttry
-catch
Block. Betrachten Sie dieses BeispielIn der ersten Version wartet die asynchrone Funktion auf das abgelehnte Versprechen, bevor sie das Ergebnis zurückgibt, wodurch die Ablehnung in eine Ausnahme umgewandelt und die
catch
Klausel erreicht wird. Die Funktion gibt somit ein Versprechen zurück, das in die Zeichenfolge "Gespeichert!" aufgelöst wird.Die zweite Version der Funktion gibt das abgelehnte Versprechen jedoch direkt zurück, ohne es innerhalb der asynchronen Funktion abzuwarten , was bedeutet, dass dies der
catch
Fall ist nicht aufgerufen wird und der Aufrufer stattdessen die Ablehnung erhält.quelle
return new Promise(function(resolve, reject) { })
innerhalb einerfor...of
Schleife und dann aufrufenresolve()
innerhalb der Schleife nach apipe()
die Programmausführung nicht pausiert, bis die Pipe abgeschlossen ist, wie gewünscht, jedoch unter Verwendungawait new Promise(...)
. Ist letztere überhaupt eine gültige / korrekte Syntax? ist es "Abkürzung" fürreturn await new Promise(...)
? Können Sie mir helfen zu verstehen, warum Letzteres funktioniert und Ersteres nicht? für Kontext, ist das Szenario , insolution 02
der diese AntwortWie in anderen Antworten erwähnt, gibt es wahrscheinlich einen leichten Leistungsvorteil, wenn das Versprechen durch direkte Rückgabe in die Luft sprudelt - einfach, weil Sie nicht zuerst auf das Ergebnis warten und es dann erneut mit einem anderen Versprechen abschließen müssen. Bisher hat jedoch noch niemand über die Optimierung von Tail Calls gesprochen .
Die Tail-Call-Optimierung oder „richtige Tail-Calls“ ist eine Technik, mit der der Interpreter den Call-Stack optimiert. Derzeit unterstützen es noch nicht viele Laufzeiten - obwohl es technisch Teil des ES6-Standards ist -, aber es ist möglich, dass in Zukunft Unterstützung hinzugefügt wird, sodass Sie sich darauf vorbereiten können, indem Sie in der Gegenwart guten Code schreiben.
Kurz gesagt, TCO (oder PTC) optimiert den Aufrufstapel, indem kein neuer Frame für eine Funktion geöffnet wird, die direkt von einer anderen Funktion zurückgegeben wird. Stattdessen wird derselbe Frame wiederverwendet.
Da PTC, das PTC unterstützt,
delay()
direkt von zurückgegeben wirddelay1Second()
, wird zuerst ein Frame fürdelay1Second()
(die äußere Funktion) geöffnet. Statt jedoch einen anderen Frame fürdelay()
(die innere Funktion) zu öffnen , wird nur der Frame wiederverwendet, der für die äußere Funktion geöffnet wurde. Dies optimiert den Stapel, da es einen Stapelüberlauf (hehe) mit sehr großen rekursiven Funktionen verhindern kann, zfibonacci(5e+25)
. Im Wesentlichen wird es eine Schleife, die viel schneller ist.PTC ist nur aktiviert, wenn die innere Funktion direkt zurückgegeben wird. Es wird nicht verwendet, wenn das Ergebnis der Funktion geändert wird, bevor es zurückgegeben wird, z. B. wenn Sie
return (delay(1000) || null)
oder hattenreturn await delay(1000)
.Aber wie gesagt, die meisten Laufzeiten und Browser unterstützen PTC noch nicht, daher macht es jetzt wahrscheinlich keinen großen Unterschied, aber es könnte nicht schaden, Ihren Code zukunftssicher zu machen.
Lesen Sie mehr in dieser Frage: Node.js: Gibt es Optimierungen für Tail-Aufrufe in asynchronen Funktionen?
quelle
Diese Frage ist schwer zu beantworten, da sie in der Praxis davon abhängt, wie Ihr Transpiler (wahrscheinlich
babel
) tatsächlich rendertasync/await
. Die Dinge, die unabhängig davon klar sind:Beide Implementierungen sollten sich gleich verhalten, obwohl die erste Implementierung möglicherweise eine weniger
Promise
in der Kette hat.Insbesondere wenn Sie das Unnötige fallen lassen
await
, würde die zweite Version keinen zusätzlichen Code vom Transpiler erfordern, während die erste dies tut.Aus Sicht der Codeleistung und des Debuggens ist die zweite Version vorzuziehen, wenn auch nur geringfügig. Die erste Version bietet jedoch einen leichten Lesbarkeitsvorteil, da sie eindeutig anzeigt, dass sie ein Versprechen zurückgibt.
quelle
undefined
) zurück und der zweite gibt a zurückPromise
.async/await
- es fällt mir viel schwerer, darüber nachzudenken. @PitaJ ist korrekt, beide Funktionen geben ein Versprechen zurück.try-catch
? In demreturn promise
Fallrejection
würde keiner gefangen werden, richtig, während es in demreturn await promise
Fall wäre, richtig?await
diese jeweils an einer Anrufstelle verwenden, ist das Ergebnis sehr unterschiedlich.Hier lasse ich einen Code praktisch, damit Sie den Unterschied verstehen können
Die Funktion "x" ist nur eine asynchrone Funktion als eine andere Funktion, wenn die Rückgabe gelöscht wird. "Mehr Code ..."
Die Variable x ist nur eine asynchrone Funktion, die wiederum eine andere asynchrone Funktion hat. Im Hauptteil des Codes rufen wir eine Wartezeit auf, um die Funktion der Variablen x aufzurufen. Wenn sie abgeschlossen ist, folgt sie der normalen Reihenfolge des Codes für "async / await", aber innerhalb der x-Funktion gibt es eine andere asynchrone Funktion, die ein Versprechen zurückgibt oder ein "Versprechen" zurückgibt. Es bleibt in der x-Funktion und vergisst den Hauptcode, das heißt, es wird das nicht gedruckt "console.log (" more code .. "), wenn wir dagegen" await "setzen, wartet es auf jede Funktion, die abgeschlossen ist und schließlich der normalen Reihenfolge des Hauptcodes folgt.
Unter dem "console.log" ("fertig 1" löschen Sie die "Rückgabe", Sie werden das Verhalten sehen.
quelle
Hier ist ein Typoskript-Beispiel, das Sie ausführen und sich davon überzeugen können, dass Sie diese "Rückkehr warten" benötigen.
quelle
Bemerkenswerter Unterschied: Die Ablehnung von Versprechungen wird an verschiedenen Stellen behandelt
return somePromise
vergehen somePromise an die Aufrufstelle undawait
somePromise zu settle bei Aufrufort (falls vorhanden). Wenn somePromise abgelehnt wird, wird es daher nicht vom lokalen catch-Block, sondern vom catch-Block der Call-Site verarbeitet.return await somePromise
Ich werde zuerst auf SomePromise warten, um mich vor Ort niederzulassen. Daher wird der Wert oder die Ausnahme zuerst lokal behandelt. => Lokaler Catch-Block wird ausgeführt, wenn ersomePromise
abgelehnt wird.Grund:
return await Promise
erwartet sowohl vor Ort als auch außerhalb,return Promise
wartet nur draußenDetaillierte Schritte:
Versprechen zurück
delay1Second()
;delay1Second()
gibt functiondelay(1000)
sofort ein Versprechen mit zurück[[PromiseStatus]]: 'pending
. Nennen wir esdelayPromise
.Promise.resolve()
( Quelle ) ein. Dadelay1Second
es sich um eine asynchrone Funktion handelt, haben wir:Promise.resolve(delayPromise)
kehrt zurück,delayPromise
ohne etwas zu tun, da die Eingabe bereits ein Versprechen ist (siehe MDN Promise.resolve ):await
wartet bis dasdelayPromise
erledigt ist.delayPromise
mit PromiseValue = 1 erfüllt ist:delayPromise
wird abgelehnt:Rückkehr warten Versprechen
delay1Second()
;delay1Second()
gibt functiondelay(1000)
sofort ein Versprechen mit zurück[[PromiseStatus]]: 'pending
. Nennen wir esdelayPromise
.delayPromise
erledigt ist.delayPromise
wird mit PromiseValue = 1 erfüllt:delayPromise
wird abgelehnt:Glossar:
Promise.[[PromiseStatus]]
wechselt vonpending
zuresolved
oderrejected
quelle