async/await innerhalb von Pfeilfunktionen (Array#map/filter)

Lesezeit: 5 Minuten

Benutzeravatar von WelcomeTo
Willkommen zu

Ich erhalte einen Kompilierzeitfehler in diesem Code:

const someFunction = async (myArray) => {
    return myArray.map(myValue => {
        return {
            id: "my_id",
            myValue: await service.getByValue(myValue);
        }
    });
};

Fehlermeldung ist:

warten ist ein reserviertes Wort

Warum kann ich es nicht so verwenden?

  • Ich glaube nicht, dass Sie asynchrone Pfeilfunktionen haben können.

    – Spitze

    27. Februar 2017 um 15:49 Uhr

  • Relevant github.com/tc39/ecmascript-asyncawait/issues/7

    – Jared Smith

    27. Februar 2017 um 15:51 Uhr

  • Um aus der verlinkten Github-Diskussion zusammenzufassen, können Sie das nicht tun, da die anonyme Funktion, die Sie als Callback übergeben, dies nicht ist async und das Innere await kann die äußere Funktion nicht beeinträchtigen.

    – Jared Smith

    27. Februar 2017 um 15:55 Uhr


  • async/await ist Teil von ES2017 (diesjähriges Release), nicht ES7 (letztes Jahr).

    – Felix Klinge

    1. März 2017 um 14:34 Uhr

Benutzeravatar von lonesomeday
eines Tages

Sie können dies nicht so tun, wie Sie es sich vorstellen, weil Sie es nicht verwenden können await wenn es nicht direkt in einem ist async Funktion.

Sinnvoll wäre es hier, die Funktion übergeben zu lassen map asynchron. Das bedeutet, dass map würde eine Reihe von Versprechen zurückgeben. Wir können dann verwenden Promise.all um das Ergebnis zu erhalten, wenn alle Versprechen zurückkehren. Wie Promise.all selbst gibt ein Versprechen zurück, die äußere Funktion muss es nicht sein async.

const someFunction = (myArray) => {
    const promises = myArray.map(async (myValue) => {
        return {
            id: "my_id",
            myValue: await service.getByValue(myValue)
        }
    });
    return Promise.all(promises);
}

  • In diesem Fall ist Array of Promises nicht langsamer als der Klassiker für ein Array?

    – Stackdave

    3. März 2018 um 6:38 Uhr

  • @stackdave Wahrscheinlich, aber der Unterschied wird daneben belanglos sein service.getByValuewas durchaus einen Netzwerkanruf beinhalten kann …

    – einsamer Tag

    3. März 2018 um 15:23 Uhr

  • danke, ich habe angefangen, es zu verwenden, sowieso ist die Lesbarkeit besser als die Geschwindigkeit, da die meisten asynchronen ES6-Techniken immer langsamer sein werden, aber wen interessiert das?

    – Stackdave

    3. März 2018 um 15:37 Uhr

  • @lonesomeday Kann dies mit Fehlern oder Drosselungen/Verzögerungen zwischen Anrufen umgehen?

    – Kyle Penell

    25. November 2019 um 20:05 Uhr

  • @KylePennell Ja. Sie müssten Fehler entweder mit a behandeln try..catch in der async-Funktion oder mit a catch Handler, bevor er von der äußeren Funktion zurückkehrt. Eine Drossel könnte vor dem eingeführt werden return in der async-Funktion.

    – einsamer Tag

    30. November 2019 um 14:41 Uhr

Wenn Sie map mit einer asynchronen Mapping-Funktion ausführen möchten, können Sie den folgenden Code verwenden:

const resultArray = await Promise.all(inputArray.map(async (i) => someAsyncFunction(i)));

Wie es funktioniert:

  • inputArray.map(async ...) gibt ein Array von Promises zurück – eines für jeden Wert in inputArray.
  • Putten Promise.all() um die Reihe von Versprechen herum wandelt es in ein einziges Versprechen um.
  • Das einzige Versprechen von Promise.all() gibt ein Array von Werten zurück – die einzelnen Versprechungen lösen jeweils einen Wert auf.
  • Wir stellen await vor dem Promise.all() sodass wir darauf warten, dass das kombinierte Versprechen aufgelöst wird, und das Array der aufgelösten Unterversprechen in der Variablen speichern resultArray.

Am Ende erhalten wir einen Ausgabewert resultArray für jeden Artikel in inputArrayabgebildet durch die Funktion someAsyncFunction. Wir müssen warten, bis alle asynchronen Funktionen aufgelöst sind, bevor das Ergebnis verfügbar ist.

Benutzeravatar von helb
helf

Das liegt daran, dass die Funktion in map ist nicht asynchronalso kannst du nicht haben erwarten in seiner return-Anweisung. Es kompiliert mit dieser Modifikation:

const someFunction = async (myArray) => {
    return myArray.map(async (myValue) => { // <-- note the `async` on this line
        return {
            id: "my_id",
            myValue: await service.getByValue(myValue)
        }
    });
};

Probieren Sie es in Babel REPL aus

Es ist also nicht möglich, eine Empfehlung zu geben, ohne den Rest Ihrer App zu sehen, aber je nachdem, was Sie versuchen zu tun, machen Sie entweder die innere asynchron funktionieren oder versuchen, eine andere Architektur für diesen Block zu finden.

Update: Wir könnten eines Tages auf Top-Level warten: https://github.com/MylesBorins/proposal-top-level-await

  • danke, positiv bewertet, aber Ihr Code gibt ein Array mit leeren Objekten zurück (dh [{}, {}]). Ich glaube, ich muss irgendwo einfügen awaitkonnte aber nicht erkennen wo

    – Willkommen zu

    27. Februar 2017 um 16:13 Uhr


  • Was bedeutet die service.getByValue Funktion aussehen?

    – helf

    27. Februar 2017 um 16:19 Uhr

  • es gibt nur ES6 Promise zurück

    – Willkommen zu

    27. Februar 2017 um 18:03 Uhr

  • Es sieht für mich so aus, als ob das OP als Endergebnis eine Reihe von Objekten mit ID erwartet, also denke ich, dass Sie es wahrscheinlich wollen return await Promise.all(myArray.map… für Gleichwertigkeit.

    – Fock

    27. Februar 2017 um 21:33 Uhr


Es werden 2 Anweisungen sein, aber verschieben Sie einfach “warten” mit der zusätzlichen Anweisung

let results = array.map((e) => fetch('....'))
results  = await Promise.all(results)

Ich habe alle diese Antworten ausprobiert, aber niemand arbeitet für meinen Fall, weil alle Antworten a zurückgeben promise Objekt nicht das result of the promise so was:

{
  [[Prototype]]: Promise
  [[PromiseState]]: "fulfilled"
  [[PromiseResult]]: Array(3)
  0: ...an object data here...
  1: ...an object data here...
  2: ...an object data here...
  length: 3
  [[Prototype]]: Array(0)
}

Dann habe ich diese Antwort https://stackoverflow.com/a/64978715/8339172 gefunden, die besagt, ob map Die Funktion ist nicht asynchron oder versprechen bewusst. Also anstatt zu verwenden await Innerhalb map Funktion verwende ich for Schleife und await das einzelne Element, weil er das gesagt hat for Schleife ist async bewusst und pausiert die Schleife.

Wenn Sie möchten, dass jeder neu zugeordnete Wert aufgelöst wird, bevor Sie mit dem nächsten fortfahren, können Sie das Array als asynchrones Iterable verarbeiten.

Unten verwenden wir eine Bibliothek iter-opsum jeden Wert in Promise neu zuzuordnen und dann ein Objekt mit aufgelöstem Wert zu erzeugen, weil map selbst sollte intern keine Versprechungen behandeln.

import {pipe, map, wait, toAsync} from 'iter-ops';

const i = pipe(
    toAsync(myArray), // make asynchronous
    map(myValue => {
        return service.getByValue(myValue).then(a => ({id: 'my_id', myValue: a}))
    }),
    wait() // wait for each promise
);

(async function() {
    for await (const a of i) {
        console.log(a); // print resulting objects
    }
})

Nach jedem Wert verwenden wir Warten um jeden neu zugeordneten Wert aufzulösen, während er generiert wird, um die Auflösungsanforderung konsistent mit der ursprünglichen Frage zu halten.

1434590cookie-checkasync/await innerhalb von Pfeilfunktionen (Array#map/filter)

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy