Я бы хотел понять, почему forEach
не очень хорошо играет с async
/ await
.
Легче, если учесть, что async
простосинтаксический сахар для функции, возвращающей обещание.
items. forEach (f) ожидает функцию f
в качестве аргумента, которую она выполняет по каждому элементу по одному за один раз до своего возврата.Он игнорирует возвращаемое значение f
.
items.forEach(await tryToProcess)
- бессмысленный эквивалент Promise.resolve(tryToProcess).then(ttp => items.forEach(ttp))
и функционально не отличается от items.forEach(tryToProcess)
.
Now tryToProcess
возвращает обещание, но forEach
игнорирует возвращаемое значение, как мы уже упоминали, поэтому игнорирует это обещание.Это плохие новости и может привести к необработанным ошибкам отклонения, поскольку все цепочки обещаний должны быть возвращены или завершены с помощью catch
для правильной обработки ошибок.
Эта ошибка равносильна забыванию await
.К сожалению, нет array.forEachAwait()
.
элементов. map (f) немного лучше, поскольку он создает массив из возвращаемых значений из f
, что в данном случаеиз tryToProcess
даст нам множество обещаний.Например, мы могли бы сделать это:
await Promise.all(items.map(tryToProcess));
... но все tryToProcess
вызовы для каждого элемента будут выполняться параллельно друг с другом.
Важно, map
запускает их параллельно.Promise.all
- это просто средство ожидания их завершения.
Как правило ...
Я всегда использую for of
вместо forEach
в async
функциях:
for (item of items) {
await tryToProcess(item);
}
... даже если в цикле нет await
, на всякий случай я добавлю его позже, чтобы избежать этого ножного пистолета.