Verwenden von async/await mit einer forEach-Schleife

Lesezeit: 6 Minuten

Verwenden von asyncawait mit einer forEach Schleife
Saad

Gibt es Probleme bei der Nutzung async/await in einem forEach Schleife? Ich versuche, eine Reihe von Dateien zu durchlaufen und await auf den Inhalt jeder Datei.

import fs from 'fs-promise'

async function printFiles () {
  const files = await getFilePaths() // Assume this works fine

  files.forEach(async (file) => {
    const contents = await fs.readFile(file, 'utf8')
    console.log(contents)
  })
}

printFiles()

Dieser Code funktioniert, aber könnte damit etwas schief gehen? Ich hatte jemanden, der mir sagte, dass Sie nicht verwenden sollten async/await in einer übergeordneten Funktion wie dieser, also wollte ich nur fragen, ob es ein Problem damit gibt.

  • warum rufst du an printFiles eine Funktion höherer Ordnung, wenn sie keine Funktion als Argument erhält oder keine Funktion als Ausgabe zurückgibt?

    – elirandav

    9. August 2020 um 17:34 Uhr

  • @KernelMode Die forEach Methode ist hier die Funktion höherer Ordnung

    – Bergi

    9. August 2020 um 18:58 Uhr

Verwenden von asyncawait mit einer forEach Schleife
Francisco Mateo

Mit ES2018 können Sie alle oben genannten Antworten erheblich vereinfachen:

async function printFiles () {
  const files = await getFilePaths()

  for await (const contents of files.map(file => fs.readFile(file, 'utf8'))) {
    console.log(contents)
  }
}

Siehe Spezifikation: Vorschlag-Async-Iteration


2018-09-10: Diese Antwort hat in letzter Zeit viel Aufmerksamkeit erregt, siehe bitte Blogbeitrag von Axel Rauschmayer für weitere Informationen zur asynchronen Iteration.

  • Ich glaube nicht, dass diese Antwort die ursprüngliche Frage beantwortet. for-await-of mit einem synchronen Iterable (in unserem Fall ein Array) deckt nicht den Fall ab, dass ein Array gleichzeitig mit asynchronen Operationen in jeder Iteration iteriert wird. Wenn ich mich nicht irre, mit for-await-of mit einer synchronen iterierbaren über Nicht-Promise-Werte ist dasselbe wie die Verwendung einer Ebene for-of.

    – Antonio Val

    9. Januar 2019 um 10:30 Uhr

  • Wie wir delegieren files Array zum fs.readFile Hier? Es dauerte von iterable?

    – Wadim Schwezow

    17. Januar 2019 um 13:34 Uhr


  • Bei Verwendung dieser Lösung würde jede Iteration auf die vorherige warten, und falls eine Operation einige lange Berechnungen durchführt oder eine lange Datei liest, würde sie die Ausführung der nächsten blockieren, anstatt alle Funktionen auf Promises abzubilden und darauf zu warten, dass sie abgeschlossen sind .

    – Rafi Henig

    11. September 2019 um 1:07 Uhr

  • Diese Antwort hat das gleiche Problem wie das OP: Es greift parallel auf alle Dateien zu. Der serialisierte Ausdruck der Ergebnisse verbirgt es lediglich.

    – Fock

    18. Februar 2021 um 13:52 Uhr

  • Diese Antwort ist falsch. files.map() gibt eine Reihe von Versprechen zurück, kein asynchroner Iteratorwofür for await wurde gemacht! Dies führt zu unbehandelten Ablehnungsabstürzen!

    – Bergi

    13. Dezember 2021 um 15:57 Uhr

  • Das funktioniert perfekt, vielen Dank. Könnten Sie erklären, was hier mit passiert Promise.resolve() und await promise;?

    – parker9

    28. März 2018 um 20:48 Uhr

  • Das ist ziemlich cool. Gehe ich richtig in der Annahme, dass die Dateien der Reihe nach gelesen werden und nicht alle auf einmal?

    – GollyJer

    9. Juni 2018 um 0:24 Uhr

  • @parker9 Promise.resolve() gibt ein bereits gelöstes zurück Promise Objekt, damit reduce hat ein Promise beginnen mit. await promise; wird auf das letzte warten Promise in der Kette zu lösen. @GollyJer Die Dateien werden nacheinander verarbeitet, eine nach der anderen.

    – Timotheus Zorn

    17. Juni 2018 um 15:00 Uhr


  • @Shay, du meinst sequentiell, nicht synchron. Dies ist immer noch asynchron – wenn andere Dinge geplant sind, werden sie hier zwischen den Iterationen ausgeführt.

    – Timotheus Zorn

    30. Mai 2019 um 16:51 Uhr


  • Wenn Sie möchten, dass die asynchronen Prozesse so schnell wie möglich abgeschlossen werden, und es Ihnen egal ist, dass sie nacheinander abgeschlossen werden, versuchen Sie eine der bereitgestellten Lösungen mit einer guten Anzahl von Upvotes, die verwendet werden Promise.all. Beispiel: Promise.all(files.map(async (file) => { /* code */ }));

    – Timotheus Zorn

    31. Januar 2020 um 16:03 Uhr


1646897708 49 Verwenden von asyncawait mit einer forEach Schleife
Antonio Wal

Die p-Iteration Das Modul auf npm implementiert die Array-Iterationsmethoden, sodass sie auf sehr einfache Weise mit async/await verwendet werden können.

Ein Beispiel mit Ihrem Fall:

const { forEach } = require('p-iteration');
const fs = require('fs-promise');

(async function printFiles () {
  const files = await getFilePaths();

  await forEach(files, async (file) => {
    const contents = await fs.readFile(file, 'utf8');
    console.log(contents);
  });
})();

1646897709 560 Verwenden von asyncawait mit einer forEach Schleife
mikemaccana

Hier sind einige forEachAsync Prototypen. Beachten Sie, dass Sie müssen await Ihnen:

Array.prototype.forEachAsync = async function (fn) {
    for (let t of this) { await fn
}

Array.prototype.forEachAsyncParallel = async function (fn) {
    await Promise.all(this.map(fn));
}

Notiz Während Sie dies in Ihren eigenen Code aufnehmen können, sollten Sie dies nicht in Bibliotheken aufnehmen, die Sie an andere verteilen (um deren Globals nicht zu verschmutzen).

1646897709 430 Verwenden von asyncawait mit einer forEach Schleife
krupesch Anadkat

Ein Bild sagt mehr als 1000 Worte – Nur für sequenzielle Annäherung


Hintergrund : Ich war letzte Nacht in einer ähnlichen Situation. Ich habe die async-Funktion als foreach-Argument verwendet. Das Ergebnis war nicht vorhersehbar. Als ich meinen Code dreimal getestet habe, lief er zweimal ohne Probleme und schlug einmal fehl. (etwas Komisches)

Endlich habe ich mich umgesehen und einige Scratchpad-Tests durchgeführt.

Szenario 1 – Wie unsequenziell kann es mit async in foreach werden

Geben Sie hier die Bildbeschreibung ein

const getPromise = (time) => { 
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`Promise resolved for ${time}s`)
    }, time)
  })
}

const main = async () => {
  const myPromiseArray = [getPromise(1000), getPromise(500), getPromise(3000)]
  console.log('Before For Each Loop')

  myPromiseArray.forEach(async (element, index) => {
    let result = await element;
    console.log(result);
  })

  console.log('After For Each Loop')
}

main();

Szenario 2 – Verwenden for - of Schleife wie oben von @Bergi vorgeschlagen

Geben Sie hier die Bildbeschreibung ein

const getPromise = (time) => { 
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`Promise resolved for ${time}s`)
    }, time)
  })
}

const main = async () => {
  const myPromiseArray = [getPromise(1000), getPromise(500), getPromise(3000)]
  console.log('Before For Each Loop')

  // AVOID USING THIS
  // myPromiseArray.forEach(async (element, index) => {
  //   let result = await element;
  //   console.log(result);
  // })

  // This works well
  for (const element of myPromiseArray) {
    let result = await element;
    console.log(result)
  }

  console.log('After For Each Loop')
}

main();

Wenn du wie ich ein kleiner Oldschooler bist, könntest du einfach die klassische for-Schleife verwenden, das geht auch 🙂

const getPromise = (time) => { 
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`Promise resolved for ${time}s`)
    }, time)
  })
}

const main = async () => {
  const myPromiseArray = [getPromise(1000), getPromise(500), getPromise(3000)]
  console.log('Before For Each Loop')

  // AVOID USING THIS
  // myPromiseArray.forEach(async (element, index) => {
  //   let result = await element;
  //   console.log(result);
  // })

  // This works well too - the classic for loop :)
  for (let i = 0; i < myPromiseArray.length; i++) {
    const result = await myPromiseArray[i];
    console.log(result);
  }

  console.log('After For Each Loop')
}

main();

Ich hoffe, das hilft jemandem, guten Tag, Prost!

  • Wenn sich jemand fragt, welches Vscode-Theme das ist – es ist das offizielle Light-Thema von Github. & Wenn sich jemand bei so einem hellen Schnappschuss die Augen verletzt hat, entschuldige ich mich 😅

    – krupesch Anadkat

    19. Mai 2021 um 4:48 Uhr

  • Ich schlage vor, den Ausdruck „Before/After Loop“ zu verwenden, würde es weniger verwirrend machen, wenn es kein „For Each Loop“ ist.

    – nah dran

    2. März um 11:49 Uhr

986890cookie-checkVerwenden von async/await mit einer forEach-Schleife

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

Privacy policy