Как выполнить асинхронные операции по очереди
Короткий ответ
await внутри цикла for...of дожидается каждой операции, прежде чем начать следующую:
const delay = (ms, value) => new Promise((resolve) => setTimeout(() => resolve(value), ms));
for (const file of ['a.txt', 'b.txt', 'c.txt']) {
const result = await delay(100, `uploaded ${file}`);
console.log(result);
}Результат:
uploaded a.txt
uploaded b.txt
uploaded c.txtКаждый шаг использует предыдущий результат
Когда шаги зависят друг от друга, просто пишите их один за другим:
const getUser = async (id) => ({ id, name: 'Anna' });
const getOrders = async (user) => [`order of ${user.name}`];
const user = await getUser(1);
const orders = await getOrders(user);
console.log(orders[0]);Результат:
order of AnnaСбор результатов
Складывайте каждый результат в массив:
const double = async (n) => n * 2;
const results = [];
for (const n of [1, 2, 3]) {
results.push(await double(n));
}
console.log(results.join(', '));Результат:
2, 4, 6Частая ошибка
forEach() не ждёт асинхронные функции. Код после него выполняется раньше, чем закончатся шаги:
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
[1, 2].forEach(async (n) => {
await delay(100);
console.log('step', n);
});
console.log('done?');Результат:
done?
step 1
step 2Функции из этого ответа
- async function — Функция, которая всегда возвращает промис и внутри которой можно использовать await.
- Array.prototype.reduce — Сводит массив к одному значению.