Асинхронные функции работают даже в тех контекстах, которые не await
или не вызывают .then()
для них, то есть я определенно могу сделать это:
async function foo() {
// async calls here
}
foo(); // no await or .then().
Это означает, что вы не можете ждать операциичтобы завершить, вы не можете использовать это значение, и, что хуже всего, вы не можете перехватить или исправить любые асинхронные ошибки, которые могут быть выброшены (или отклонены, если мы будем точны)
Основное различие заключается вчто .forEach()
не заботится и не ждет завершения операций перед вызовом следующей (поскольку асинхронные функции return
немедленно), тогда как ваш вызов for..of
использует await
для ожидания завершения каждой операции перед перемещениемк следующему.
Ваш первый пример .forEach
будет примерно эквивалентен нижнему, если вы удалите await
из вызова внутри цикла.
В результате получается, чтоВаш первый пример возвращает Обещание, которое разрешается немедленно, а не после того, как все ваши вызовы БД были завершены, поэтому тест ожидает завершения операций, но это не так.Во втором примере вы правильно await
завершаете все вызовы до завершения асинхронной функции, поэтому возвращаемое обещание будет разрешено только после того, как все вызовы разрешатся, во-первых.
На этомобратите внимание, что эти два примера не эквивалентны, поскольку первый будет вызывать insertMany один за другим, не дожидаясь их завершения, в результате чего вызовы БД будут выполняться параллельно.
Если вы хотите сохранить это поведение, но по-прежнему возвращаете правильное Обещание, которое ожидает завершения всего, вы должны использовать [].map()
вместо [].forEach
:
const writeToDB = async (db, data) => {
const dataKeys = Object.keys(data)
const allPromises = dataKeys.map(async key =>
await db.collection(key).insertMany(data[key])) // run all calls in parallel
return await Promise.all(allPromises); // wait for them all to finish
}