Rolf B: async await Chaos

Beitrag lesen

Hallo Herr Bert,

das liegt daran, dass reduce nicht darauf ausgelegt ist, mit Promises zu arbeiten.

Dein übriger Code ist übrigens merkwürdig - warum erzeugst Du eine Konstante main, der Du eine Pfeilfunktion zuweist, die Du als IIFE verwendest? Die Pfeilfunktion gibt nichts zurück, in main steht nachher also undefined. Möglicherweise ist das in deinem eigenen Code umfangreicher und ergibt mehr Sinn, aber wenn Du nichts weiter willst, als asynchrone Funktionen awaiten zu können, dann lass das. Gib deinem Script type="module" und gut ist. Der IE ist tot, man kann ECMAScript-Module ohne Bedenken verwenden. In denen ist ein await auf Top-Ebene erlaubt.

Aber zu deinem Problem.

Du hast ein Array von zwei Funktionen und setzt reduce darauf an. Diese Funktionen sind offenbar async-Funktionen, denn Du awaitest ihren Rückgabewert.

reduce ruft den Callback für fetchNMutate1 auf und übergibt die Werte 0 und fetchNMutate1.

Im Callback rufst Du fetchNMutate1 auf und übergibst die 0. Das Ergebnis von fetchNMutate1 erwartest Du mit await - und damit das möglich ist, machst Du auch den ganzen Callback async.

Aber was passiert nun? Eine async-Methode gibt nicht den Wert zurück, den Du mit return zurückgibst, sondern ein Promise, dass Du awaiten kannst und von dem Du dann den Wert bekommst.

Heißt also: reduce schert sich nicht um dein await im ersten Callback, sondern bekommt das Promise deines asynchronen Callbacks.

Der zweite Callback wird demnach mit acc=[Promise] und cur=fetchNMutate2 aufgerufen.

Dieses Promise übergibst Du an fetchNMutate2, wo aber eigentlich ein Akkumulatorwert erwartet wird.

Du musst also das Promise, dass Du in acc bekommst, erstmal awaiten, und deswegen auch für den Startwert ein Promise übergeben.

<script type="module">
  const funcs = [fetchNmutate1, fetchNmutate2];
  const endergebnis = await funcs.reduce(async (accP, cur) => {
    const acc = await accP;
    const zwischenergebnis = await cur(acc);
    return zwischenergebnis;
  }, Promise.resolve(0));
</script>

Scheußlich. Wirklich scheußlich. Gelle?

Ich hätte da was für Dich:

<script type="module">
  const funcs = [fetchNmutate1, fetchNmutate2];
  let acc = 0;
  for (let func of funcs) {
     acc = await func(acc);
  }
</script>

oder als async-Funktion mit Array-Parameter für die Funktionen

<script type="module">
  async function collectFetchesAsync(funcArray) {
    let acc = 0;
    for (let func of funcArray) {
       acc = await func(acc);
    }
    return acc;
  }

  const ergebnis = await collectFetchesAsync( [fetchNmutate1, fetchNmutate2] );
</script>

oder als async-Funktion mit Rest-Parameter

<script type="module">
  async function collectFetchesAsync(...funcs) {
    let acc = 0;
    for (let func of funcs) {
       acc = await func(acc);
    }
    return acc;
  }

  const ergebnis = collectFetchesAsync(fetchNmutate1, fetchNmutate2);
</script>

Besser? Array.prototype.reduce ist LÄNGST nicht immer die beste Wahl.

Rolf

--
sumpsi - posui - obstruxi