Nehmen Sie die folgende Schleife:
for(var i=0; i<100; ++i){
let result = await some_slow_async_function();
do_something_with_result();
}
Hat
await
blockieren die Schleife? Oder wird dasi
während desawait
Ing weiter erhöht ?Ist die Reihenfolge der
do_something_with_result()
garantierten Reihenfolge in Bezug aufi
? Oder hängt es davon ab, wie schnell dieawait
ed-Funktion für jede isti
?
javascript
async-await
Smorgs
quelle
quelle
await Promise.all(arr)
sollte oder ob dieses Formular korrekt war und etwas anderes die gewünschte Asynchronität behinderte. Wenn ichawait
für alle eine Single mache , müsste ich mich darauf einlassen, umPromise.map
mit jeder fertig zu werden. Ich.then
frage mich, ob es in dieser Situation besser ist als asynchron / warten.Promise.all
darauf macht das etwas anderes - ob es noch richtig (oder noch wünschenswerter) ist, hängt von Ihren Anforderungen ab.async
Operation ausgeführt wird, die eine externe Ressource umfasst, z. B. Datenbank, Datei-E / A.Antworten:
"Block" ist nicht das richtige Wort, aber ja, ich werde nicht weiter erhöht, während ich warte. Stattdessen springt die Ausführung zurück zu dem Ort, an dem die
async
Funktion aufgerufen wurde, und gibt ein Versprechen als Rückgabewert aus. Der Rest des nach dem Funktionsaufruf folgenden Codes wird fortgesetzt, bis der Codestapel geleert wurde. Wenn das Warten beendet ist, wird der Status der Funktion wiederhergestellt und die Ausführung innerhalb dieser Funktion fortgesetzt. Immer wenn diese Funktion zurückkehrt (abgeschlossen wird), wird das entsprechende Versprechen - das zuvor zurückgegeben wurde - aufgelöst.Die Bestellung ist garantiert. Der Code, der auf folgt,
await
wird garantiert erst ausgeführt, nachdem der Aufrufstapel geleert wurde, dh zumindest bei oder nach der Ausführung der nächsten Mikrotask.Sehen Sie, wie die Ausgabe in diesem Snippet ist. Beachten Sie insbesondere, wo "nach dem Aufruf von test" steht:
async function test() { for (let i = 0; i < 2; i++) { console.log('Before await for ', i); let result = await Promise.resolve(i); console.log('After await. Value is ', result); } } test().then(_ => console.log('After test() resolved')); console.log('After calling test');
quelle
async/await
bis vor kurzem mit Generatoren / implementiert wurdeyield
. Wenn man es so betrachtet, wird alles klarer. Ich werde diese Antwort akzeptieren.then
als mit Generatoren. Es werden nur "Zurückspringen an den Ort, an dem es aufgerufen wurde" und "Zustand der Funktion wird wiederhergestellt" angezeigtyield
..then
aber nicht soawait
, also denkeyield
ich daran , dass es meine Verwirrung löst.Wie @realbart sagt, blockiert es die Schleife, wodurch die Aufrufe sequentiell werden.
Wenn Sie eine Menge erwartbarer Vorgänge auslösen und dann alle zusammen ausführen möchten, können Sie Folgendes tun:
const promisesToAwait = []; for (let i = 0; i < 100; i++) { promisesToAwait.push(fetchDataForId(i)); } const responses = await Promise.all(promisesToAwait);
quelle
promisesToAwait
Array wird niemals Versprechen enthalten.Sie können async / await in einer "FOR LOOP" wie folgt testen:
(async () => { for (let i = 0; i < 100; i++) { await delay(); console.log(i); } })(); function delay() { return new Promise((resolve, reject) => { setTimeout(resolve, 100); }); }
quelle
Anzeige 1. Ja. Nein.
Anzeige 2. Ja. Nein.
Beweis:
Code-Snippet anzeigen
async function start() { console.log('Start'); for (var i = 0; i < 10; ++i) { let result = await some_slow_async_function(i); do_something_with_result(i); } console.log('Finish'); } function some_slow_async_function(n) { return new Promise(res => setTimeout(()=>{ console.log(`Job done: ${(2000/(1+n))|0} ms`); res(true); },2000/(1+n))); } function do_something_with_result(n) { console.log(`Something ${n}`); } start();
quelle
Keine Ereignisschleife ist nicht blockiert, siehe Beispiel unten
function sayHelloAfterSomeTime (ms) { return new Promise((resolve, reject) => { if (typeof ms !== 'number') return reject('ms must be a number') setTimeout(() => { console.log('Hello after '+ ms / 1000 + ' second(s)') resolve() }, ms) }) } async function awaitGo (ms) { await sayHelloAfterSomeTime(ms).catch(e => console.log(e)) console.log('after awaiting for saying Hello, i can do another things ...') } function notAwaitGo (ms) { sayHelloAfterSomeTime(ms).catch(e => console.log(e)) console.log('i dont wait for saying Hello ...') } awaitGo(1000) notAwaitGo(1000) console.log('coucou i am event loop and i am not blocked ...')
quelle
Hier ist meine Testlösung zu dieser interessanten Frage:
import crypto from "crypto"; function diyCrypto() { return new Promise((resolve, reject) => { crypto.pbkdf2('secret', 'salt', 2000000, 64, 'sha512', (err, res) => { if (err) { reject(err) return } resolve(res.toString("base64")) }) }) } setTimeout(async () => { console.log("before await...") const a = await diyCrypto(); console.log("after await...", a) }, 0); setInterval(() => { console.log("test....") }, 200);
Innerhalb des Rückrufs von setTimeout
await
blockiert die Ausführung. Aber dassetInterval
läuft weiter, so dass die Ereignisschleife wie gewohnt läuft.quelle
async
Funktionen geben ein Versprechen zurück, bei dem es sich um ein Objekt handelt, das schließlich in einen Wert "aufgelöst" oder mit einem Fehler "abgelehnt" wird. Dasawait
Schlüsselwort bedeutet warten, bis dieser Wert (oder Fehler) abgeschlossen ist.Aus Sicht der laufenden Funktion wird das Warten auf das Ergebnis der langsamen asynchronen Funktion blockiert . Die Javascript-Engine hingegen erkennt, dass diese Funktion blockiert ist und auf das Ergebnis wartet. Daher überprüft sie die Ereignisschleife (z. B. neue Mausklicks oder Verbindungsanfragen usw.), um festzustellen, ob andere Dinge vorhanden sind Es kann so lange bearbeitet werden, bis die Ergebnisse zurückgegeben werden.
Beachten Sie jedoch, dass die Javascript-Engine nicht viele Ressourcen hat, um andere Aufgaben zu erledigen, wenn die langsame Async-Funktion langsam ist, weil sie viele Dinge in Ihrem Javascript-Code berechnet (und wenn Sie andere Dinge tun, würde dies wahrscheinlich die langsame Async-Funktion bewirken noch langsamer). Der Vorteil von Async-Funktionen liegt in E / A-intensiven Vorgängen wie dem Abfragen einer Datenbank oder dem Übertragen einer großen Datei, bei der die Javascript-Engine wirklich auf etwas anderes wartet (z. B. Datenbank, Dateisystem usw.).
Die folgenden zwei Codebits sind funktional äquivalent:
let result = await some_slow_async_function();
und
let promise = some_slow_async_function(); // start the slow async function // you could do other stuff here while the slow async function is running let result = await promise; // wait for the final value from the slow async function
Im zweiten Beispiel oben wird die langsame asynchrone Funktion ohne das
await
Schlüsselwort aufgerufen , sodass die Ausführung der Funktion gestartet und ein Versprechen zurückgegeben wird. Dann können Sie andere Dinge tun (wenn Sie andere Dinge zu tun haben). Dann wird dasawait
Schlüsselwort verwendet, um zu blockieren, bis das Versprechen tatsächlich "aufgelöst" wird. Aus der Sicht derfor
Schleife läuft sie also synchron.Damit:
Ja, das
await
Schlüsselwort hat den Effekt, dass die laufende Funktion blockiert wird , bis die asynchrone Funktion entweder mit einem Wert "aufgelöst" oder mit einem Fehler "zurückgewiesen" wird, aber die Javascript-Engine nicht blockiert, die andere Dinge tun kann, wenn sie andere hat Dinge zu tun, während Sie wartenJa, die Ausführung der Schleife erfolgt sequentiell
Unter http://javascript.info/async gibt es ein großartiges Tutorial dazu .
quelle
await
auftritt, und die Codeausführung wird nach dem Funktionsaufruf fortgesetzt.await
festgestellt wird. Die Funktion kehrt zurück und die Codeausführung wird wie nach jedem Funktionsaufruf fortgesetzt . Die Ereignisschleife spielt nur dann eine Rolle, wenn der Aufrufstapel leer ist, was nicht der Fall ist, wenn erawait
auftritt. Übrigens: Bei dieser Frage geht es nicht speziell um Node, sondern um JavaScript im Allgemeinen.await
) hat Vorrang vor Mausklicks und anderen agentengesteuerten Ereignissen.Nein, warten wird die Schleife nicht blockieren. Ja, wird
i
während der Schleife weiter erhöht.Die Reihenfolge
do_something_with_result()
wird nacheinander garantiert, jedoch nicht in Bezug aufi
. Dies hängt davon ab, wie schnell die erwartete Funktion ausgeführt wird.Alle Aufrufe an
some_slow_async_function()
werden gestapelt, dh wenn dies ado_something_with_result()
war , wird angezeigt,console
wie oft die Schleife ausgeführt wird. Danach werden nacheinander alle erwarteten Aufrufe ausgeführt.Zum besseren Verständnis können Sie das folgende Code-Snippet ausführen:
async function someFunction(){ for (let i=0;i<5;i++){ await callAPI(); console.log('After', i, 'th API call'); } console.log("All API got executed"); } function callAPI(){ setTimeout(()=>{ console.log("I was called at: "+new Date().getTime())}, 1000); } someFunction();
Man kann deutlich sehen, wie die Zeile
console.log('After', i, 'th API call');
zuerst für die gesamte Strecke der for-Schleife gedruckt wird und dann am Ende, wenn der gesamte Code ausgeführt wird, Ergebnisse erhaltencallAPI()
.Wenn also Leitungen nach dem Warten vom Ergebnis der Warte-Anrufe abhängen, funktionieren sie nicht wie erwartet.
Zusammenfassend lässt sich sagen, dass
await
infor-loop
keine erfolgreiche Operation für das Ergebnis von Warteanrufen gewährleistet ist , deren Abschluss einige Zeit in Anspruch nehmen kann.Wenn man im Knoten eine
neo-async
Bibliothek mit verwendetwaterfall
, kann man dies erreichen.quelle
await callAPI()
sofort zurück. Wenn Sie Ihre änderncallAPI()
, um ein Versprechen zurückzugeben, wird es funktionieren.