Использование async / await с циклом forEach

Есть ли проблемы с использованием _1 _ / _ 2_ в forEach цикле? Я пытаюсь перебрать массив файлов и await содержимое каждого файла.

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()

Этот код работает, но может что-то с этим не так? Кто-то сказал мне, что вы не должны использовать _6 _ / _ 7_ в такой функции высшего порядка, как эта, поэтому я просто хотел спросить, есть ли здесь какие-либо проблемы.


person Saad    schedule 01.06.2016    source источник
comment
почему вы вызываете printFiles функцию высшего порядка, если она не принимает функцию в качестве аргумента или не возвращает функцию в качестве вывода?   -  person KernelMode    schedule 09.08.2020
comment
@KernelMode Метод forEach является здесь функцией высшего порядка   -  person Bergi    schedule 09.08.2020


Ответы (27)


Конечно, код работает, но я почти уверен, что он не делает то, что вы ожидаете. Он просто запускает несколько асинхронных вызовов, но функция printFiles сразу же возвращается после этого.

Чтение по порядку

Если вы хотите читать файлы последовательно, вы действительно не можете использовать forEach. Просто используйте вместо этого современный for … of цикл, в котором await будет работать должным образом:

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

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

Чтение параллельно

Если вы хотите читать файлы параллельно, вы действительно не можете использовать forEach. Каждый из вызовов функции обратного вызова async действительно возвращает обещание, но вы их отбрасываете, а не ждете. Просто используйте вместо этого map, и вы можете дождаться массива обещаний, который вы получите с Promise.all:

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

  await Promise.all(files.map(async (file) => {
    const contents = await fs.readFile(file, 'utf8')
    console.log(contents)
  }));
}
person Bergi    schedule 01.06.2016
comment
Не могли бы вы объяснить, почему for ... of ... работает? - person Demonbane; 15.08.2016
comment
хорошо, я знаю, почему ... Использование Babel преобразует _1 _ / _ 2_ в функцию генератора, а использование forEach означает, что каждая итерация имеет отдельную функцию генератора, которая не имеет ничего общего с другими. поэтому они будут выполняться независимо и не будут иметь контекста next() с другими. Фактически, простой цикл for() также работает, потому что итерации также выполняются в одной единственной функции генератора. - person Demonbane; 15.08.2016
comment
@Demonbane: Короче говоря, потому что он был разработан для работы :-) await приостанавливает текущую оценку функции, включая все управляющие структуры. Да, в этом отношении он очень похож на генераторы (поэтому они используются для полифилла async / await). - person Bergi; 16.08.2016
comment
Итак, files.map(async (file) => ... эквивалентно files.map((file) => new Promise((rej, res) => { ...? - person arve0; 29.03.2017
comment
@ arve0 Не совсем, функция async сильно отличается от обратного вызова Promise исполнителя, но да, обратный вызов map возвращает обещание в обоих случаях. - person Bergi; 29.03.2017
comment
Когда вы приходите, чтобы узнать о обещаниях JS, но вместо этого используйте полчаса для перевода на латынь. Надеюсь, ты горд @Bergi;) - person Félix Adriyel Gagnon-Grenier; 17.05.2017
comment
Это лучший ответ: await Promise.all(_.map(arr, async (val) => {...}); решил мою проблему. Конечно, каждый обратный вызов async возвращает обещание, которого я не ожидал. - person Adi Sivasankaran; 23.02.2018
comment
Для тех, кто не знает, обещайте . all возвращает одно обещание, которое выполняется, когда разрешены все обещания в массиве. (в основном ждет завершения всех обещаний) - person Doug; 02.03.2018
comment
Я думаю, что второй абзац должен быть таким. Если вы хотите читать файлы параллельно, вы не можете использовать for..of? Поскольку вы можете читать файлы параллельно с forEach, просто это будет выглядеть очень некрасиво, потому что вы не можете await это. - person doubleOrt; 20.03.2018
comment
@Taurus Если вы не собираетесь их ждать, то for…of будет работать одинаково с forEach. Нет, я действительно имею в виду этот абзац, чтобы подчеркнуть, что в современном JS-коде нет места .forEach. - person Bergi; 20.03.2018
comment
@Bergi Разве это не плохо для производительности? Если вам нужно сделать 3 запроса, вы не можете сделать их все параллельно, поэтому, если каждый занимает одну секунду, ваша программа будет запускаться за 3 секунды. Но если вы используете map или forEach, запросы будут выполняться параллельно. - person doubleOrt; 20.03.2018
comment
@ Таурус, я не понимаю. Что в сравнении с чем плохо для производительности? - person Bergi; 20.03.2018
comment
for..of плохо сказывается на производительности по сравнению с _2 _ / _ 3_, потому что for..of будет останавливаться на каждой итерации, поэтому, если я сделаю 3 запроса, каждый запрос должен будет ждать завершения предыдущих запросов. Но с _5 _ / _ 6_ все запросы будут выполняться параллельно. - person doubleOrt; 20.03.2018
comment
@Taurus Нет. queries.forEach(q => asyncRequest(q)); делает то же самое, что и for (const q of queries) asyncRequest(q);. Нет никакой разницы в производительности, и оба будут выполнять запросы параллельно. Конечно, ни в том, ни в другом случае ждать ничего нельзя - как это сделать, смотрите в моем ответе. - person Bergi; 20.03.2018
comment
@Taurus Да, это в основном два подхода из моего ответа. Ни один из них не использует forEach. В чем проблема? - person Bergi; 20.03.2018
comment
@Bergi Я мог бы использовать forEach (работал бы так же, как map относительно времени выполнения). Но, как вы можете видеть из моих предыдущих комментариев, я говорил либо о forEach, либо о map в сравнении с for..of. Я сказал: for..of плохо сказывается на производительности по сравнению с forEach / map. - person doubleOrt; 20.03.2018
comment
Однако как это правда (из вашего ответа): Если вы хотите читать файлы параллельно, вы действительно не можете использовать forEach. Я думаю, вы можете сделать то же самое, что и ваш пример map, за исключением с forEach это будет выглядеть некрасиво и непригодно для _3 _ / _ 4_. - person doubleOrt; 20.03.2018
comment
@Taurus Но это неправильно: for…of неплохо по производительности по сравнению с forEach, если использовать его таким же непригодным образом, ничего не ожидая. И да, нельзя использовать средство непригодно. - person Bergi; 20.03.2018
comment
@Bergi Вы предлагаете случай, когда вы не делаете await никаких запросов внутри for..of? Если да, хорошо, но вы согласны с тем, что ваш второй пример более производительный, чем ваш первый? - person doubleOrt; 20.03.2018
comment
@Taurus Да, это то, что я написал в своем комментарии выше. Конечно, это не имеет никакого смысла и не подходит для решения проблемы OP, независимо от того, с forEach или for…of. И нет, я бы вообще не стал сравнивать эти два (_3 _ + _ 4_ vs _5 _ + _ 6_) с точки зрения производительности - они просто разные во многих других, более важных отношениях. Выбор последовательного или параллельного выполнения - это решение, которое включает в себя множество других факторов, и, конечно, параллельное выполнение обычно завершается быстрее. - person Bergi; 20.03.2018
comment
@Bergi Конечно, бывают случаи, когда for..of может быть единственным выходом (например, если каждый запрос зависит от предыдущего запроса), но новичок всегда может выбрать решение for..of, потому что оно проще. - person doubleOrt; 20.03.2018
comment
@Bergi Однако я до сих пор не понимаю, насколько это правильно: Если вы хотите читать файлы параллельно, вы действительно не можете использовать forEach. - person doubleOrt; 20.03.2018
comment
@Taurus Вы не можете использовать его, потому что не можете дождаться результата. Конечно, если бы вы использовали его - как это сделал OP - тогда они работали бы параллельно, но forEach абсолютно непригоден, как вы сами сказали. - person Bergi; 20.03.2018
comment
@Bergi О, теперь я понимаю, что вы имеете в виду под этой частью. Но это действительно расплывчато, потому что технически вы можете его использовать, но это не значит, что вам нужно. Ваш ответ в основном означает, что параллельный запуск запросов с использованием forEach невозможен. - person doubleOrt; 20.03.2018
comment
@Taurus Я подумал и подождал, пока он закончится, подразумевалось. Но все же, если не может передать то же, что и совершенно не должно, я в порядке. Сделайте это простым для новичков: им не следует никогда использовать forEach, это все, что им нужно знать. - person Bergi; 20.03.2018
comment
или вы могли бы быть так любезны, чтобы предложить альтернативные цели-обманщики, которые не делают уродливых вещей, таких как var promises = []; array.forEach(value => { promises.push(someAsync(value)); }); return Promise.all(promises);, потому что я вижу много таких, или подобных вопросов с лучшими ответами, но код слишком сложен, чтобы его можно было повторно использовать в качестве дубликата цель. - person Patrick Roberts; 08.05.2019
comment
@PatrickRoberts Я даже веду их список, потому что когда-нибудь я напишу новый канонический вопрос с подробными ответами ... - person Bergi; 08.05.2019
comment
Для параллельного метода с картой массива, если нет необходимости что-либо делать в обратном вызове после разрешения обещания: await Promise.all (files.map ((file) = ›fs.readFile (file, 'utf8'))) ; - person Maciej Krawczyk; 14.12.2020
comment
почему вы использовали await до Promise.all(files.map(async (file) => {, если вы ничего не делаете с возвращенным значением? какие-либо специальные ответы, которые вы должны использовать await, даже если вы ничего не делаете с возвращаемым значением? - person masterG; 14.01.2021
comment
@masterG Чтобы он ждал, прежде чем выполнить (или отклонить) обещание, которое было возвращено вызывающей стороне printFiles. Конечно, можно было бы также return добавить Promise.all, но await - это использование по умолчанию, которое мне нужно было продемонстрировать с ответом. - person Bergi; 14.01.2021
comment
Ты спасатель. На всю жизнь я не мог понять, почему Object.entries ({}). ForEach не возвращает желаемый результат. Переключил его на: for (let [k, v] of Object.entries ({})) {...}, и теперь он отлично работает. Спасибо! - person 010011100101; 14.03.2021
comment
Отличное решение ... !!! - person Dhaduk Mitesh; 27.03.2021
comment
Обалденно просто обалденно. - person Shashank Dubey; 05.07.2021
comment
Ого, это все меняет. Хороший ответ, это прекрасно работает. - person Bruno; 14.07.2021

С ES2018 вы можете значительно упростить все вышеперечисленные ответы на следующие вопросы:

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

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

См. Спецификацию: Предложение-асинхронная-итерация


2018-09-10: этот ответ в последнее время привлекает много внимания, см. Axel Сообщение в блоге Раушмайера для получения дополнительной информации об асинхронной итерации.

person Francisco Mateo    schedule 15.06.2018
comment
Не уверен, где определено file. Это перенесено 1: 1 из вопроса выше. - person Francisco Mateo; 08.09.2018
comment
Почему люди поддерживают этот ответ? Присмотритесь к ответу, вопросу и предложению. После of должна быть асинхронная функция, которая вернет массив. Это не работает, и Франциско сказал; - person Yevhenii Herasymchuk; 08.01.2019
comment
Я не думаю, что этот ответ отвечает на первоначальный вопрос. for-await-of с синхронной итерацией (в нашем случае это массив) не распространяется на случай одновременной итерации массива с использованием асинхронных операций на каждой итерации. Если я не ошибаюсь, использование for-await-of с синхронной итерацией по значениям, не являющимся обещаниями, аналогично использованию простого for-of. - person Antonio Val; 09.01.2019
comment
Как мы здесь делегируем массив files fs.readFile? Это требует от итерабельности? - person Vadim Shvetsov; 17.01.2019
comment
Используя это решение, каждая итерация будет ждать предыдущей, и в случае, если операция выполняет некоторые длинные вычисления или читает длинный файл, она блокирует выполнение следующей, в отличие от сопоставления всех функций с обещаниями и ожидания их завершения. . - person Rafi Henig; 11.09.2019
comment
Этот ответ имеет ту же проблему, что и OP: он обращается ко всем файлам параллельно. Последовательная печать результатов просто скрывает это. - person jib; 18.02.2021
comment
Основная проблема с этим ответом заключается в том, что в for await при использовании итератора синхронизации, такого как массив, карта должна возвращать обещание. В узле fs по умолчанию не является асинхронным ... использование fsPromises заставит это работать параллельно. Я думаю, что стоит обратить внимание на этот превосходный, хорошо поддерживаемый синтаксис. - person Ray Foss; 27.04.2021
comment
это просто потрясающе, спасибо. - person Lord; 14.07.2021

Вместо Promise.all в сочетании с Array.prototype.map (что не гарантирует порядок разрешения Promise) я использую Array.prototype.reduce, начиная с решенного Promise:

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

  await files.reduce(async (promise, file) => {
    // This line will wait for the last async function to finish.
    // The first iteration uses an already resolved Promise
    // so, it will immediately continue.
    await promise;
    const contents = await fs.readFile(file, 'utf8');
    console.log(contents);
  }, Promise.resolve());
}
person Timothy Zorn    schedule 26.03.2018
comment
Это отлично работает, большое вам спасибо. Не могли бы вы объяснить, что здесь происходит с Promise.resolve() и await promise;? - person parrker9; 28.03.2018
comment
Это довольно круто. Правильно ли я полагаю, что файлы будут прочитаны по порядку, а не все сразу? - person GollyJer; 09.06.2018
comment
@ parrker9 Promise.resolve() возвращает уже разрешенный объект Promise, так что reduce имеет Promise для начала. await promise; будет ждать разрешения последнего Promise в цепочке. @GollyJer Файлы будут обрабатываться последовательно, по одному. - person Timothy Zorn; 17.06.2018
comment
Очень круто использовать reduce, спасибо за комментарий! Я просто обозначу, что, в отличие от некоторых других методов, упомянутых в комментариях, этот является синхронным, что означает, что файлы читаются один за другим, а не параллельно (поскольку следующая итерация функции сокращения зависит от предыдущей итерация, она должна быть синхронной). - person Shay Yzhakov; 30.05.2019
comment
@Shay, ты имеешь ввиду последовательный, а не синхронный. Это по-прежнему асинхронно - если запланированы другие действия, они будут выполняться здесь между итерациями. - person Timothy Zorn; 30.05.2019
comment
Есть ли способ сделать это явно быстрым, если у вас есть страница Express, которой требуется список ресурсов для отображения ...? - person ; 30.01.2020
comment
Если вам нужно, чтобы асинхронные процессы завершались как можно быстрее, и вы не заботитесь о том, чтобы они выполнялись последовательно, попробуйте одно из предоставленных решений с большим количеством голосов, в котором используется Promise.all. Пример: Promise.all(files.map(async (file) => { /* code */ })); - person Timothy Zorn; 31.01.2020
comment
мой любимый вариант, хотелось бы увидеть родной Promise.chain() вроде all() - person Remi Mélisson; 18.03.2021

Модуль p-iteration в npm реализует методы итерации массива, поэтому их можно использовать в очень простых путь с async / await.

Пример с вашим случаем:

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);
  });
})();
person Antonio Val    schedule 10.07.2017

Вот несколько forEachAsync прототипов. Обратите внимание, что вам нужно await их:

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

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

Примечание, хотя вы можете включить это в свой собственный код, вам не следует включать это в библиотеки, которые вы распространяете другим (чтобы не загрязнять их глобальные файлы).

person Matt    schedule 22.03.2018
comment
использование: ждать myArray. forEachAsyncParallel (async (item) = ›{await myAsyncFunction (item)}) - person Damien Romito; 02.06.2021

В дополнение к ответу @ Bergi я хотел бы предложить третью альтернативу. Он очень похож на второй пример @ Bergi, но вместо ожидания каждого readFile по отдельности вы создаете массив обещаний, каждое из которых ожидаете в конце.

import fs from 'fs-promise';
async function printFiles () {
  const files = await getFilePaths();

  const promises = files.map((file) => fs.readFile(file, 'utf8'))

  const contents = await Promise.all(promises)

  contents.forEach(console.log);
}

Обратите внимание, что функция, переданная в .map(), не обязательно должна быть async, поскольку fs.readFile в любом случае возвращает объект Promise. Следовательно, promises - это массив объектов Promise, которые можно отправить в Promise.all().

В ответе @ Bergi консоль может регистрировать содержимое файлов в том порядке, в котором они были прочитаны. Например, если действительно маленький файл заканчивает чтение до действительно большого файла, он будет зарегистрирован первым, даже если маленький файл появится после большого файла в массиве files. Однако в моем методе, описанном выше, вам гарантируется, что консоль будет регистрировать файлы в том же порядке, что и предоставленный массив.

person chharvey    schedule 23.02.2018

довольно безболезненно добавить в файл пару методов, которые будут обрабатывать асинхронные данные в сериализованном порядке и придадут более традиционный вид вашему коду. Например:

module.exports = function () {
  var self = this;

  this.each = async (items, fn) => {
    if (items && items.length) {
      await Promise.all(
        items.map(async (item) => {
          await fn(item);
        }));
    }
  };

  this.reduce = async (items, fn, initialValue) => {
    await self.each(
      items, async (item) => {
        initialValue = await fn(initialValue, item);
      });
    return initialValue;
  };
};

теперь, предполагая, что он сохранен в './myAsync.js', вы можете сделать что-то подобное приведенному ниже в соседнем файле:

...
/* your server setup here */
...
var MyAsync = require('./myAsync');
var Cat = require('./models/Cat');
var Doje = require('./models/Doje');
var example = async () => {
  var myAsync = new MyAsync();
  var doje = await Doje.findOne({ name: 'Doje', noises: [] }).save();
  var cleanParams = [];

  // FOR EACH EXAMPLE
  await myAsync.each(['bork', 'concern', 'heck'], 
    async (elem) => {
      if (elem !== 'heck') {
        await doje.update({ $push: { 'noises': elem }});
      }
    });

  var cat = await Cat.findOne({ name: 'Nyan' });

  // REDUCE EXAMPLE
  var friendsOfNyanCat = await myAsync.reduce(cat.friends,
    async (catArray, friendId) => {
      var friend = await Friend.findById(friendId);
      if (friend.name !== 'Long cat') {
        catArray.push(friend.name);
      }
    }, []);
  // Assuming Long Cat was a friend of Nyan Cat...
  assert(friendsOfNyanCat.length === (cat.friends.length - 1));
}
person Jay Edwards    schedule 22.09.2017
comment
Незначительное дополнение, не забудьте заключить await / asyncs в блоки try / catch !! - person Jay Edwards; 26.09.2017

Это решение также оптимизировано для памяти, поэтому вы можете запускать его для 10 000 элементов данных и запросов. Некоторые другие решения приведут к сбою сервера при работе с большими наборами данных.

В TypeScript:

export async function asyncForEach<T>(array: Array<T>, callback: (item: T, index: number) => void) {
        for (let index = 0; index < array.length; index++) {
            await callback(array[index], index);
        }
    }

Как пользоваться?

await asyncForEach(receipts, async (eachItem) => {
    await ...
})
person Oliver Dixon    schedule 16.04.2020

Решение Берги прекрасно работает, когда fs основано на обещаниях. Вы можете использовать для этого bluebird, fs-extra или fs-promise.

Однако решение для собственной библиотеки fs узла выглядит следующим образом:

const result = await Promise.all(filePaths
    .map( async filePath => {
      const fileContents = await getAssetFromCache(filePath, async function() {

        // 1. Wrap with Promise    
        // 2. Return the result of the Promise
        return await new Promise((res, rej) => {
          fs.readFile(filePath, 'utf8', function(err, data) {
            if (data) {
              res(data);
            }
          });
        });
      });

      return fileContents;
    }));

Примечание. require('fs') обязательно принимает функцию в качестве третьего аргумента, в противном случае выдается ошибка:

TypeError [ERR_INVALID_CALLBACK]: Callback must be a function
person master_dodo    schedule 26.05.2019

Оба решения выше работают, однако Антонио выполняет работу с меньшим количеством кода, вот как это помогло мне разрешить данные из моей базы данных из нескольких разных дочерних ссылок, а затем поместить их все в массив и разрешить его в обещании, в конце концов, сделано:

Promise.all(PacksList.map((pack)=>{
    return fireBaseRef.child(pack.folderPath).once('value',(snap)=>{
        snap.forEach( childSnap => {
            const file = childSnap.val()
            file.id = childSnap.key;
            allItems.push( file )
        })
    })
})).then(()=>store.dispatch( actions.allMockupItems(allItems)))
person Hooman Askari    schedule 26.08.2017

Картинка объемом 1000 слов - только для последовательного подхода


Предыстория. Прошлой ночью я был в похожей ситуации. Я использовал асинхронную функцию в качестве аргумента foreach. Результат был непредсказуемым. Когда я 3 раза тестировал свой код, он 2 раза работал без проблем и 1 раз не удался. (что-то странное)

Наконец я собрался с мыслями и провел несколько тестов с блокнотом.

Сценарий 1. Насколько непоследовательным может быть асинхронность в foreach

введите описание изображения здесь

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();

Сценарий 2 - Использование цикла for - of, как предложено выше @Bergi

введите описание изображения здесь

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();

Если вы немного олдскульный, как я, вы можете просто использовать классический цикл for, который тоже работает :)

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();

Надеюсь, это кому-то поможет, добрый день, ура!

person krupesh Anadkat    schedule 19.05.2021
comment
Если кому-то интересно, что это за тема vscode - это официальная светлая тема github. & Если кто-то поранил глаза таким ярким снимком, мои извинения ???? - person krupesh Anadkat; 19.05.2021

Одно важное предостережение: метод await + for .. of и метод forEach + async на самом деле имеют разный эффект.

Наличие await внутри реального for цикла гарантирует, что все асинхронные вызовы выполняются один за другим. И способ forEach + async запустит все обещания одновременно, что быстрее, но иногда перегружает (если вы выполняете какой-либо запрос к БД или посещаете некоторые веб-службы с ограничениями по объему и не хотите отправлять 100 000 вызовов вовремя).

Вы также можете использовать reduce + promise (менее элегантно), если вы не используете async/await и хотите, чтобы файлы читались один за другим.

files.reduce((lastPromise, file) => 
 lastPromise.then(() => 
   fs.readFile(file, 'utf8')
 ), Promise.resolve()
)

Или вы можете создать forEachAsync, чтобы помочь, но в основном использовать то же самое для цикла, лежащего в основе.

Array.prototype.forEachAsync = async function(cb){
    for(let x of this){
        await cb(x);
    }
}
person LeOn - Han Li    schedule 24.09.2017

Просто добавив к исходному ответу

  • Синтаксис параллельного чтения в исходном ответе иногда сбивает с толку и труден для чтения, возможно, мы можем написать его другим подходом.
async function printFiles() {
  const files = await getFilePaths();
  const fileReadPromises = [];

  const readAndLogFile = async filePath => {
    const contents = await fs.readFile(file, "utf8");
    console.log(contents);
    return contents;
  };

  files.forEach(file => {
    fileReadPromises.push(readAndLogFile(file));
  });

  await Promise.all(fileReadPromises);
}

  • Для последовательной работы, а не только для for ... of, также будет работать обычный цикл for.
async function printFiles() {
  const files = await getFilePaths();

  for (let i = 0; i < files.length; i++) {
    const file = files[i];
    const contents = await fs.readFile(file, "utf8");
    console.log(contents);
  }
}

person gsaandy    schedule 01.12.2019

Как ответ @Bergi, но с одним отличием.

Promise.all отвергает все обещания, если одно из них отклоняется.

Итак, используйте рекурсию.

const readFilesQueue = async (files, index = 0) {
    const contents = await fs.readFile(files[index], 'utf8')
    console.log(contents)

    return files.length <= index
        ? readFilesQueue(files, ++index)
        : files

}

const printFiles async = () => {
    const files = await getFilePaths();
    const printContents = await readFilesQueue(files)

    return printContents
}

printFiles()

PS

readFilesQueue находится за пределами printFiles вызывает побочный эффект *, представленный console.log, лучше высмеивать, тестировать или шпионить, поэтому не круто иметь функцию, которая возвращает содержимое (примечание).

Следовательно, код может быть просто спроектирован таким образом: три отдельные функции, которые являются «чистыми» ** и не вызывают побочных эффектов, обрабатывают весь список и могут быть легко изменены для обработки неудачных случаев.

const files = await getFilesPath()

const printFile = async (file) => {
    const content = await fs.readFile(file, 'utf8')
    console.log(content)
}

const readFiles = async = (files, index = 0) => {
    await printFile(files[index])

    return files.lengh <= index
        ? readFiles(files, ++index)
        : files
}

readFiles(files)

Будущее изменение / текущее состояние

Узел поддерживает ожидание верхнего уровня (у него еще нет плагина, его не будет и его можно включить с помощью флагов гармонии), это круто, но не решает одну проблему (стратегически я работаю только над LTS-версиями). Как получить файлы?

Использование композиции. Учитывая код, у меня возникает ощущение, что он находится внутри модуля, поэтому у меня должна быть функция для этого. Если нет, вам следует использовать IIFE, чтобы обернуть код роли в асинхронную функцию, создающую простой модуль, который сделает все за вас, или вы можете пойти правильным путем, например, с композицией.

// more complex version with IIFE to a single module
(async (files) => readFiles(await files())(getFilesPath)

Обратите внимание, что имя переменной изменяется из-за семантики. Вы передаете функтор (функцию, которая может быть вызвана другой функцией) и получаете указатель на память, которая содержит начальный блок логики приложения.

Но, если это не модуль и вам нужно экспортировать логику?

Оберните функции в асинхронную функцию.

export const readFilesQueue = async () => {
    // ... to code goes here
}

Или поменять имена переменных, как угодно ...


* побочным эффектом означает любой совместный эффект приложения, который может изменить статус / поведение или вызвать ошибки в приложении, такие как ввод-вывод.

** "чистым", это апостроф, так как функции не чистые, и код может быть преобразован в чистую версию, когда нет вывода на консоль, только манипуляции с данными.

Помимо этого, чтобы быть чистым, вам нужно будет работать с монадами, которые обрабатывают побочные эффекты, подвержены ошибкам и обрабатывают эту ошибку отдельно от приложения.

person lukaswilkeer    schedule 21.12.2019

Простое решение для замены неработающего цикла ожидания forEach() - замена forEach на map и добавление Promise.all( в начало.

Например:

await y.forEach(async (x) => {

to

await Promise.all(y.map(async (x) => {

В конце нужен дополнительный ).

person yeah22    schedule 27.01.2021

Нецелесообразно вызывать асинхронный метод из цикла. Это связано с тем, что каждая итерация цикла будет откладываться до завершения всей асинхронной операции. Это не очень эффективно. Это также предотвращает преимущества распараллеливания _1 _ / _ 2_.

Лучшим решением было бы создать все обещания сразу, а затем получить доступ к результатам с помощью Promise.all(). В противном случае каждая последующая операция не начнется, пока не будет завершена предыдущая.

Следовательно, код можно реорганизовать следующим образом;

const printFiles = async () => {
  const files = await getFilePaths();
  const results = [];
  files.forEach((file) => {
    results.push(fs.readFile(file, 'utf8'));
  });
  const contents = await Promise.all(results);
  console.log(contents);
}
person Johnz    schedule 02.04.2021
comment
Также нецелесообразно открывать сразу тысячи файлов для одновременного их чтения. Всегда нужно оценивать, что лучше: последовательный, параллельный или смешанный. Последовательные циклы не так уж и плохи, await фактически делает их возможными. Кроме того, они не лишены преимуществ асинхронного выполнения, поскольку вы все равно можете запускать несколько таких циклов одновременно (например, два одновременных вызова printFiles). - person Bergi; 02.04.2021

Используя Task, Futurize и Traversable List, вы можете просто сделать

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

  List(files).traverse( Task.of, f => readFile( f, 'utf-8'))
    .fork( console.error, console.log)
}

Вот как вы это настроили

import fs from 'fs';
import { futurize } from 'futurize';
import Task from 'data.task';
import { List } from 'immutable-ext';

const future = futurizeP(Task)
const readFile = future(fs.readFile)

Другой способ структурировать желаемый код - это

const printFiles = files => 
  List(files).traverse( Task.of, fn => readFile( fn, 'utf-8'))
    .fork( console.error, console.log)

Или, возможно, даже более функционально ориентированный

// 90% of encodings are utf-8, making that use case super easy is prudent

// handy-library.js
export const readFile = f =>
  future(fs.readFile)( f, 'utf-8' )

export const arrayToTaskList = list => taskFn => 
  List(files).traverse( Task.of, taskFn ) 

export const readFiles = files =>
  arrayToTaskList( files, readFile )

export const printFiles = files => 
  readFiles(files).fork( console.error, console.log)

Затем из родительской функции

async function main() {
  /* awesome code with side-effects before */
  printFiles( await getFiles() );
  /* awesome code with side-effects after */
}

Если вам действительно нужна большая гибкость в кодировании, вы можете просто сделать это (для удовольствия, я использую предлагаемый Оператор прямой переадресации)

import { curry, flip } from 'ramda'

export const readFile = fs.readFile 
  |> future,
  |> curry,
  |> flip

export const readFileUtf8 = readFile('utf-8')

PS - Я не пробовал этот код на консоли, могут быть опечатки ... "прямой фристайл, с вершины купола!" как сказали бы дети 90-х. :-п

person Babakness    schedule 28.02.2018

В настоящее время свойство прототипа Array.forEach не поддерживает асинхронные операции, но мы можем создать нашу собственную поли-заливку в соответствии с нашими потребностями.

// Example of asyncForEach Array poly-fill for NodeJs
// file: asyncForEach.js
// Define asynForEach function 
async function asyncForEach(iteratorFunction){
  let indexer = 0
  for(let data of this){
    await iteratorFunction(data, indexer)
    indexer++
  }
}
// Append it as an Array prototype property
Array.prototype.asyncForEach = asyncForEach
module.exports = {Array}

Вот и все! Теперь у вас есть метод async forEach, доступный для любых массивов, определенных после них для операций.

Давай проверим ...

// Nodejs style
// file: someOtherFile.js

const readline = require('readline')
Array = require('./asyncForEach').Array
const log = console.log

// Create a stream interface
function createReader(options={prompt: '>'}){
  return readline.createInterface({
    input: process.stdin
    ,output: process.stdout
    ,prompt: options.prompt !== undefined ? options.prompt : '>'
  })
}
// Create a cli stream reader
async function getUserIn(question, options={prompt:'>'}){
  log(question)
  let reader = createReader(options)
  return new Promise((res)=>{
    reader.on('line', (answer)=>{
      process.stdout.cursorTo(0, 0)
      process.stdout.clearScreenDown()
      reader.close()
      res(answer)
    })
  })
}

let questions = [
  `What's your name`
  ,`What's your favorite programming language`
  ,`What's your favorite async function`
]
let responses = {}

async function getResponses(){
// Notice we have to prepend await before calling the async Array function
// in order for it to function as expected
  await questions.asyncForEach(async function(question, index){
    let answer = await getUserIn(question)
    responses[question] = answer
  })
}

async function main(){
  await getResponses()
  log(responses)
}
main()
// Should prompt user for an answer to each question and then 
// log each question and answer as an object to the terminal

Мы могли бы сделать то же самое для некоторых других функций массива, таких как map ...

async function asyncMap(iteratorFunction){
  let newMap = []
  let indexer = 0
  for(let data of this){
    newMap[indexer] = await iteratorFunction(data, indexer, this)
    indexer++
  }
  return newMap
}

Array.prototype.asyncMap = asyncMap

... и так далее :)

Несколько замечаний:

  • Ваша функция iteratorFunction должна быть асинхронной функцией или обещанием
  • Для массивов, созданных до Array.prototype.<yourAsyncFunc> = <yourAsyncFunc>, эта функция недоступна.
person Beau    schedule 12.03.2019

Сегодня я нашел для этого несколько решений. Запуск функций async await в цикле forEach Loop. Создавая оболочку вокруг, мы можем добиться этого.

Более подробное объяснение того, как это работает внутренне, для собственного forEach, и почему он не может выполнять вызов асинхронной функции, а другие сведения о различных методах представлены по ссылке здесь

Есть несколько способов, которыми это можно сделать, и они заключаются в следующем:

Метод 1: Использование обертки.

await (()=>{
     return new Promise((resolve,reject)=>{
       items.forEach(async (item,index)=>{
           try{
               await someAPICall();
           } catch(e) {
              console.log(e)
           }
           count++;
           if(index === items.length-1){
             resolve('Done')
           }
         });
     });
    })();

Метод 2: использование того же самого, что и универсальная функция Array.prototype

Array.prototype.forEachAsync.js

if(!Array.prototype.forEachAsync) {
    Array.prototype.forEachAsync = function (fn){
      return new Promise((resolve,reject)=>{
        this.forEach(async(item,index,array)=>{
            await fn(item,index,array);
            if(index === array.length-1){
                resolve('done');
            }
        })
      });
    };
  }

Использование :

require('./Array.prototype.forEachAsync');

let count = 0;

let hello = async (items) => {

// Method 1 - Using the Array.prototype.forEach 

    await items.forEachAsync(async () => {
         try{
               await someAPICall();
           } catch(e) {
              console.log(e)
           }
        count++;
    });

    console.log("count = " + count);
}

someAPICall = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("done") // or reject('error')
        }, 100);
    })
}

hello(['', '', '', '']); // hello([]) empty array is also be handled by default

Способ 3:

Использование Promise.all

  await Promise.all(items.map(async (item) => {
        await someAPICall();
        count++;
    }));

    console.log("count = " + count);

Метод 4: традиционный цикл for или современный цикл for

// Method 4 - using for loop directly

// 1. Using the modern for(.. in..) loop
   for(item in items){

        await someAPICall();
        count++;
    }

//2. Using the traditional for loop 

    for(let i=0;i<items.length;i++){

        await someAPICall();
        count++;
    }


    console.log("count = " + count);
person PranavKAndro    schedule 24.11.2019
comment
Ваши методы 1 и 2 являются просто неправильными реализациями, в которых нужно было использовать Promise.all - они не принимают во внимание ни один из многих крайних случаев. - person Bergi; 25.11.2019
comment
@Bergi: Спасибо за правильные комментарии. Не могли бы вы объяснить мне, почему методы 1 и 2 неверны. Это также служит цели. Это очень хорошо работает. Это означает, что все эти методы возможны, в зависимости от ситуации, когда можно решить выбрать один из них. У меня есть работающий пример того же. - person PranavKAndro; 25.11.2019
comment
Он не работает с пустыми массивами, у него нет обработки ошибок и, возможно, других проблем. Не изобретайте велосипед. Просто используйте Promise.all. - person Bergi; 25.11.2019
comment
В определенных условиях, когда это невозможно, это будет полезно. Также обработка ошибок по умолчанию выполняется forEach api, так что никаких проблем. Об этом позаботились! - person PranavKAndro; 26.11.2019
comment
Нет, нет условий, при которых Promise.all невозможно, но _2 _ / _ 3_ возможно. И нет, forEach абсолютно не обрабатывает никаких ошибок обещаний. - person Bergi; 26.11.2019
comment
Конус на Берги, дело не в том, что лучше, а в различных доступных решениях. Вы упомянули обработку ошибок как пустой массив, обработка ошибок пустого массива выполняется внутри forEach. Давай закончим этот разговор здесь. Опять же, это все возможные способы достижения - person PranavKAndro; 26.11.2019
comment
Речь идет не о том, что хорошо или лучше от пула действительных решений, а о том, что ваш код полностью сломан. Вы пробовали, что происходит, когда вы передаете пустой массив? Он висит вечно. Вы пробовали, что происходит, когда someAPICall() отклоняет? Вы получаете необработанный отказ от обещания, и он зависает навсегда. - person Bergi; 26.11.2019
comment
@Bergi: Обычно, если какой-либо разработчик использует async await для ожидания обещания, тогда он должен быть окружен ловушкой попытки. someAPICall () - это не оболочка, которую я предоставляю, это функция разработчика, которую разработчик записывает внутри обратного вызова, который я предоставляю как часть оболочки, разработчик должен окружить это с помощью try catch. Если вы хотите, я могу обновить ответ, обрабатывается пустой массив, вы запускаете и даете мне знать. Работает отлично. - person PranavKAndro; 27.11.2019
comment
разработчик должен окружить это try catch - но вы этого не сделали. Если вы думаете, что это всегда нужно делать, да, пожалуйста, по крайней мере, сделайте это самостоятельно. Но нет, обычно ожидается, что обещание, возвращаемое forEachAsync(…), должно быть отклонено. И нет, ваш код не обрабатывает пустые массивы, вы пробовали? await [].forEachAsync(() => {}); console.log("never happens"); - person Bergi; 27.11.2019

Вы можете использовать Array.prototype.forEach, но async / await несовместимы. Это связано с тем, что обещание, возвращаемое из асинхронного обратного вызова, ожидает разрешения, но Array.prototype.forEach не разрешает никаких обещаний из выполнения своего обратного вызова. Итак, вы можете использовать forEach, но вам придется самостоятельно обрабатывать разрешение обещаний.

Вот способ читать и распечатывать каждый файл последовательно, используя Array.prototype.forEach

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

  let promiseChain = Promise.resolve()
  files.forEach((file) => {
    promiseChain = promiseChain.then(() => {
      fs.readFile(file, 'utf8').then((contents) => {
        console.log(contents)
      })
    })
  })
  await promiseChain
}

Вот способ (все еще использующий Array.prototype.forEach) для параллельной печати содержимого файлов

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

  const promises = []
  files.forEach((file) => {
    promises.push(
      fs.readFile(file, 'utf8').then((contents) => {
        console.log(contents)
      })
    )
  })
  await Promise.all(promises)
}
person richytong    schedule 20.05.2020
comment
Первый сенарио идеально подходит для циклов, которые нужно запускать последовательно, и вы не можете использовать их для - person Mark Odey; 29.05.2020

Чтобы увидеть, как это может пойти не так, напечатайте console.log в конце метода.

Что в целом может пойти не так:

  • Произвольный заказ.
  • printFiles может завершить работу перед печатью файлов.
  • Низкая производительность.

Это не всегда неправильно, но часто встречается в стандартных случаях использования.

Как правило, использование forEach приводит ко всем, кроме последнего. Он будет вызывать каждую функцию, не дожидаясь ее, то есть он сообщает всем функциям о запуске, а затем завершает работу, не дожидаясь завершения функций.

import fs from 'fs-promise'

async function printFiles () {
  const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'))

  for(const file of files)
    console.log(await file)
}

printFiles()

Это пример нативного JS, который сохранит порядок, предотвратит преждевременный возврат функции и теоретически сохранит оптимальную производительность.

Это будет:

  • Инициируйте параллельное чтение всех файлов.
  • Сохраняйте порядок с помощью map для сопоставления имен файлов с обещаниями, которых нужно ждать.
  • Дождитесь каждого обещания в порядке, определенном массивом.

С помощью этого решения первый файл будет отображаться, как только он станет доступен, не дожидаясь, пока сначала станут доступны другие.

Он также будет загружать все файлы одновременно, вместо того, чтобы ждать завершения первого, прежде чем можно будет начать чтение второго файла.

Единственный недостаток этого и исходной версии заключается в том, что если одновременно запускается несколько операций чтения, то обрабатывать ошибки труднее из-за того, что за один раз может произойти больше ошибок.

В версиях, которые читают файл за раз, тогда остановится в случае сбоя, не тратя время на попытки прочитать другие файлы. Даже с тщательно продуманной системой отмены может быть трудно избежать сбоя в первом файле, но уже при чтении большинства других файлов.

Производительность не всегда предсказуема. Хотя многие системы будут работать быстрее с параллельным чтением файлов, некоторые предпочтут последовательное. Некоторые из них являются динамическими и могут смещаться под нагрузкой. Оптимизация, предполагающая задержку, не всегда обеспечивает хорошую пропускную способность в условиях сильной конкуренции.

В этом примере также нет обработки ошибок. Если что-то требует, чтобы они были либо успешно показаны, либо не показывались вообще, этого не произойдет.

Рекомендуется поэкспериментировать с console.log на каждом этапе и решениями для чтения поддельных файлов (вместо этого - случайная задержка). Хотя многие решения, кажется, делают то же самое в простых случаях, все они имеют тонкие различия, которые требуют некоторой дополнительной проверки, чтобы избавиться от них.

Используйте этот макет, чтобы понять разницу между решениями:

(async () => {
  const start = +new Date();
  const mock = () => {
    return {
      fs: {readFile: file => new Promise((resolve, reject) => {
        // Instead of this just make three files and try each timing arrangement.
        // IE, all same, [100, 200, 300], [300, 200, 100], [100, 300, 200], etc.
        const time = Math.round(100 + Math.random() * 4900);
        console.log(`Read of ${file} started at ${new Date() - start} and will take ${time}ms.`)
        setTimeout(() => {
          // Bonus material here if random reject instead.
          console.log(`Read of ${file} finished, resolving promise at ${new Date() - start}.`);
          resolve(file);
        }, time);
      })},
      console: {log: file => console.log(`Console Log of ${file} finished at ${new Date() - start}.`)},
      getFilePaths: () => ['A', 'B', 'C', 'D', 'E']
    };
  };

  const printFiles = (({fs, console, getFilePaths}) => {
    return async function() {
      const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'));

      for(const file of files)
        console.log(await file);
    };
  })(mock());

  console.log(`Running at ${new Date() - start}`);
  await printFiles();
  console.log(`Finished running at ${new Date() - start}`);
})();

person jgmjgm    schedule 14.10.2019

Вот отличный пример использования async в цикле forEach.

Напишите свой собственный asyncForEach

async function asyncForEach(array, callback) {  
    for (let index = 0; index < array.length; index++) {
        await callback(array[index], index, array)
    }
}

Вы можете использовать это так

await asyncForEach(array, async function(item,index,array){
     //await here
   }
)
person ChenZeTong    schedule 11.02.2021

Подобно p-iteration Антонио Вала, альтернативным модулем npm является _ 2_:

const AsyncAF = require('async-af');
const fs = require('fs-promise');

function printFiles() {
  // since AsyncAF accepts promises or non-promises, there's no need to await here
  const files = getFilePaths();

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

printFiles();

В качестве альтернативы async-af имеет статический метод (log / logAF), который регистрирует результаты. обещаний:

const AsyncAF = require('async-af');
const fs = require('fs-promise');

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

  AsyncAF(files).forEach(file => {
    AsyncAF.log(fs.readFile(file, 'utf8'));
  });
}

printFiles();

Однако основным преимуществом библиотеки является то, что вы можете связать асинхронные методы, чтобы делать что-то вроде:

const aaf = require('async-af');
const fs = require('fs-promise');

const printFiles = () => aaf(getFilePaths())
  .map(file => fs.readFile(file, 'utf8'))
  .forEach(file => aaf.log(file));

printFiles();

async-af

person Scott Rudiger    schedule 21.06.2018

Как уже упоминалось в других ответах, вы, вероятно, хотите, чтобы он выполнялся последовательно, а не параллельно. Т.е. запустить для первого файла, дождаться завершения, затем, когда он будет завершен, запустить для второго файла. Этого не случится.

Я думаю, что важно выяснить, почему этого не происходит.

Подумайте, как работает forEach. Я не могу найти источник, но предполагаю, что он работает примерно так:

const forEach = (arr, cb) => {
  for (let i = 0; i < arr.length; i++) {
    cb(arr[i]);
  }
};

А теперь подумайте, что произойдет, если вы сделаете что-то вроде этого:

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

Внутри цикла forEach for мы вызываем cb(arr[i]), который в итоге оказывается logFile(file). У функции logFile есть await внутри, поэтому, возможно, цикл for будет ждать этого await, прежде чем перейти к i++?

Нет, не будет. Как ни странно, await работает не так. Из документов:

Ожидание разделяет поток выполнения, позволяя вызывающей асинхронной функции возобновить выполнение. После того, как ожидание откладывает продолжение асинхронной функции, следует выполнение последующих операторов. Если это ожидание является последним выражением, выполненным его функцией, выполнение продолжается, возвращая вызывающей функции ожидающее обещание для завершения функции ожидания и возобновляя выполнение этого вызывающего.

Таким образом, если у вас есть следующее, номера не будут регистрироваться до "b":

const delay = (ms) => {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
};

const logNumbers = async () => {
  console.log(1);
  await delay(2000);
  console.log(2);
  await delay(2000);
  console.log(3);
};

const main = () => {
  console.log("a");
  logNumbers();
  console.log("b");
};

main();

Возвращаясь к forEach, forEach похоже на main, а logFile похоже на logNumbers. main не остановится только потому, что logNumbers сделает какое-то awaiting, а forEach не остановится только потому, что logFile сделает какое-то await.

person Adam Zerner    schedule 23.12.2020

Если вы хотите перебирать все элементы одновременно:

async function asyncForEach(arr, fn) {
  await Promise.all(arr.map(fn));
}

Если вы хотите перебирать все элементы одновременно (например, когда ваша функция сопоставления имеет побочные эффекты или запуск сопоставителя сразу для всех элементов массива был бы слишком затратным по ресурсам):

Вариант А. Обещания

function asyncForEachStrict(arr, fn) {
  return new Promise((resolve) => {
    arr.reduce(
      (promise, cur, idx) => promise
        .then(() => fn(cur, idx, arr)),
      Promise.resolve(),
    ).then(() => resolve());
  });
}

Вариант Б: асинхронный / ожидание

async function asyncForEachStrict(arr, fn) {
  for (let idx = 0; idx < arr.length; idx += 1) {
    const cur = arr[idx];

    await fn(cur, idx, arr);
  }
}
person Wojciech Maj    schedule 19.11.2020
comment
Ваш вариант a включает в себя Promise антипаттерн конструктора . - person Bergi; 19.11.2020

exports.getTat = async function () {
  for (const tatfcp of resp[0]) {
    const getProductResponcekey = params.pincode + '-' + tatfcp.productid + '-' + result[tatfcp.productid].reqQty + '-' + tatfcp.groups[0].dispatchwarehouseid;
    const redisResp = await redis.getRedis(getProductResponcekey);
    if (redisResp) {
      products.push(redisResp[0]);
      console.log('redis', redisResp[0]);
    } else {
      const getProductResponceData = await getProductResponce(resp[1], resp[2], params.pincode, tatfcp, data[1], data[2], data[8], gstandvendordata[1], data[9]);
      products.push(getProductResponceData);
      redis.setRedis(getProductResponcekey, getProductResponceData, config.redis.expiryTime1Day);
    }
  }
};

Это мое решение

person suraj gholap    schedule 21.07.2021

Я бы использовал хорошо протестированные (миллионы загрузок в неделю) pify и async модули. Если вы не знакомы с асинхронным модулем, я настоятельно рекомендую вам ознакомиться с его документами. Я видел, как несколько разработчиков тратят время на воссоздание своих методов или, что еще хуже, на создание сложного в обслуживании асинхронного кода, когда асинхронные методы более высокого порядка упрощают код.

const async = require('async')
const fs = require('fs-promise')
const pify = require('pify')

async function getFilePaths() {
    return Promise.resolve([
        './package.json',
        './package-lock.json',
    ]);
}

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

  await pify(async.eachSeries)(files, async (file) => {  // <-- run in series
  // await pify(async.each)(files, async (file) => {  // <-- run in parallel
    const contents = await fs.readFile(file, 'utf8')
    console.log(contents)
  })
  console.log('HAMBONE')
}

printFiles().then(() => {
    console.log('HAMBUNNY')
})
// ORDER OF LOGS:
// package.json contents
// package-lock.json contents
// HAMBONE
// HAMBUNNY
```

person Zachary Ryan Smith    schedule 04.02.2018
comment
Это шаг в неверном направлении. Вот руководство по сопоставлению, которое я создал, чтобы помочь людям застрять в аду обратных вызовов в современную эру JS: github.com/jmjpro/async-package-to-async-await/blob/master/. - person jbustamovej; 20.02.2018
comment
как вы можете видеть здесь, меня интересует и открыты для использования async / await вместо async lib. Сейчас я думаю, что у каждого есть время и место. Я не уверен, что async lib == callback hell и async / await == современная эпоха JS. imo, когда async lib ›async / await: 1. сложный поток (например, очередь, груз, даже автоматически, когда что-то усложняется) 2. параллелизм 3. поддержка массивов / объектов / итераций 4. обработка ошибок - person Zachary Ryan Smith; 21.02.2018