Rolf B: async await Chaos

Beitrag lesen

Hallo Herr Bert,

Echt top, wie viel Zeit hier manche in ihnen völlig unbekannte Individuen stecken!

Ja, ich muss schon verrückt sein 😉

Aber tatsächlich lerne ich durch das Analysieren der Probleme anderer auch selbst immer wieder dazu. Ganz uneigennützig ist das also nicht. Und es tut ab und zu auch mal gut, wenn einem jemand zuhört.

Die Motivation der anderen Foristen mag eine andere sein. Einige sind Lehrer, vermutlich tut's auch denen gut, wenn zur Abwechslung mal jemand zuhört…

muss ich als Startwert tatsächlich Promise.resolve(0) übergeben, oder wäre nicht auch einfach 0 gangbar?

Das Problem ist, dass dein async-Callback auf jeden Fall ein Promise zurückgibt. Weil er async ist. Und weil der Rückgabewert des reduce-Callbacks der neue acc Wert ist, kommt spätestens ab dem zweiten Aufruf des Callbacks ein Promise als acc Wert an und wenn Du das nicht awaitest, kommst Du an seinen Wert nicht 'ran.

Wegen des await auf den acc Wert musst Du auch als Initialwert ein Promise hineingeben. Weil Du etwas anderes nicht awaiten kannst. Oder möchtest Du im Callback etwa abfragen, ob acc ein Promise ist oder nicht? Dann doch lieber den Startwert in ein Promise verpacken.~~

Und nun habe ich etwas gelernt. Man kann nicht nur Promises awaiten. Jeder andere Wert wird einfach durch den await durchgereicht. Ts.

Ich habe noch mehr gelernt. Der Wert wird nicht durch den await durchgereicht. JavaScript verpackt ihn ihn ein Promise, damit auf jeden Fall das await-Timing stattfindet. Du kannst also als Initialwert 0 übergeben. JavaScript macht in dem Moment, wo Du 0 awaiten willst, automagisch ein Promise.resolve(0) daraus.

Wird aber ein Promise nicht sofort resolved, wenn es nichts zu resolven gibt?

Doch, wird es. Aber du kannst auch Promises awaiten, die schon erfüllt sind. Es ist auch der einzige Weg, um an ihren Wert heranzukommen. Was nicht heißt, dass dieser await NICHT wartet. Was hinter await steht, wird immre im then-Callback des awaiteten Promise ausgeführt und damit in die Microtask-Queue verlagert.

Was irgendwie beeindruckend ist. Die reduce-Methode weiß überhaupt gar nichts von all dem. D.h. sie läuft blindlings durch und erzeugt einen Riesenschwanz an Promises, die sich erst danach Stück für Stück erfüllen.

async function test() {
  let numbers = [ 1, 2, 3, 4, 5, 6 ];

  let pSum = numbers.reduce( async (pAcc, curr) => {
                console.log("will reduce " + curr);
                let acc = await pAcc;
                let newAcc = await computeAsync(acc, curr);
                console.log("reduce " + curr + " - newAcc is " + newAcc);
                return newAcc;
             });

  console.log("reduce done");

  let sum = await pSum;
  console.log(sum);
}

test();
console.log("Test done");

Überleg mal, in welcher Reihenfolge die Ausgaben wohl kommen. Ohne auszuprobieren 😉

Und du weißt ja, dass ein await nichts weiter ist als Syntaxzucker für einen then-Callback?

console.log("Vorher");
let a = await doAsync(234);
console.log("Nachher: ", a);

ist EXAKT das gleiche wie

console.log("Vorher");
doAsync(234)
.then(a => {
   console.log("Nachher: ", a);
});

Aufgabe für schlaflose Nächte: Schreibe dein await-Zeug in die zuckerfreie Variante mit .then um. Aber spätestens dann wirst Du einsehen, warum ich diese await-Orgie "scheußlich" nannte.

Rolf

--
sumpsi - posui - obstruxi