Использование async/await c Array.map в TypeScript: решение ошибок
Пройдите тест, узнайте какой профессии подходите
Быстрый ответ
// Функция для параллельной обработки набора асинхронных задач
async function asyncMap(array, asyncFn) {
return Promise.all(array.map(item => asyncFn(item)));
}
// Пример (Простые вычисления) 🧮:
const results = await asyncMap([1, 2, 3], async num => {
return num * 2; // Асинхронное действие — это удвоение чисел
});
console.log(results); // Вывод: [2, 4, 6]
При использовании Array.map
вы стартуете асинхронные операции одновременно. Далее, с помощью Promise.all
, вы ожидаете их завершения. Функция asyncMap
максимально прозрачна. В представленном примере мы удвоили числа для иллюстрации.
Понимание комбинаторов Promise: Фантастическая четвёрка
Если перед вами встаёт задача работать с множеством промисов, изучите следующие комбинаторы Promise:
Promise.all
: Ждёт выполнения всех промисов.Promise.allSettled
: Поддерживает обработку успешно завершившихся и с ошибкой операций.Promise.any
: Отмечает первый успешно выполненный промис.Promise.race
: Принцип «Кто быстрее выполнился (или "упал") — тот и победил».
Чаще всего вы будете выбирать Promise.all
, но в ситуациях, когда вам важно знать результат каждой операции, независимо от её исхода, Promise.allSettled
может быть полезным решением.
Обработка исключений: Будьте готовым ко всему
При выполнении асинхронного маппинга стоит обратить внимание на порядок выполнения. В этом поможет обработка исключений:
async function safeAsyncMap(array, asyncFn) {
try {
return await Promise.all(array.map(item => asyncFn(item)));
} catch (error) {
console.error("Обнаружено исключение:", error);
}
}
Использование try/catch
с await Promise.all
поможет нам отслеживать исключения и обрабатывать их эффективно, не позволяя приложению аварийно завершиться.
Улучшение читабельности: Краткость — сестра таланта
Стрелочные функции в Array.map
позволяют кратко и ясно описать асинхронные операции:
const asyncOperation = async item => {
/* Здесь происходит магия асинхронной операции. */
};
const results = await Promise.all(items.map(asyncOperation));
С помощью стрелочных функций и async/await мы существенно упрощаем код и делаем его более наглядным.
TypeScript: Порядок в JavaScript
С использованием TypeScript вы получите типовую безопасность при работе с Array.map
, что снижает вероятность ошибок и предупреждает возможные сбои в системе.
Визуализация
Представьте применение async/await
с Array.map
в виде группы фотографов (📸), которые одновременно фотографируют различные пейзажи 🏞️:
| Фотограф (📸) | Пейзаж (🏞️) | Действие |
| ------------- | ------------ | -------------- |
| 📸 1 | 🏞️ A | Фотографировать |
| 📸 2 | 🏞️ B | Фотографировать |
| 📸 3 | 🏞️ C | Фотографировать |
Процесс совпадает с логикой работы Array.map
. Но вот проявка пленки — это асинхронный процесс!
let developedPhotos = await Promise.all(scenicSpots.map(async (spot) => {
return await developPicture(spot);
}));
После проявки:
Результат проявки: [🖼️ A, 🖼️ B, 🖼️ C]
Фотографии делаются всеми сразу, но каждая проявляется поочерёдно. Именно так работает Array.map
с async/await.
Тестирование асинхронного итерирования
Для тестирования асинхронного маппинга можно имитировать асинхронные процессы. Функция randomDelay
отлично подойдёт для имитации сетевых задержек или задержек при файловых операциях на ввод/вывод:
function randomDelay(val) {
return new Promise(resolve => setTimeout(() => {
console.log(`Муторное ожидание? Вот здесь ваш ${val}.`);
resolve(val);
}, Math.random() * 1000));
}
let testResults = await Promise.all(arr.map(async n => await randomDelay(n)));
Тестирование с внесением искусственных задержек поможет удостовериться, что ваш код ведёт себя корректно в асинхронной среде.
Библиотека Bluebird: Незаменимый помощник Promise
Bluebird предлагает метод Promise.map()
. Он регулирует параллелизм выполнения — отличное решение для конкретных задач:
let Bluebird = require('bluebird'); // Птицы ни при чём 🐦
let results = await Bluebird.map(array, asyncFn, { concurrency: 2 }); // Ограничение до 2 асинхронных вызовов одновременно
Такой подход позволяет более эффективно распределять системные ресурсы при большом количестве асинхронных операций.
Выжимка производительности
При работе с большим количеством данных или сложными операциями оптимизация становится важной:
- Ограничение параллелизма: Контролируйте количество одновременных операций, чтобы не перегружать цикл отслеживания событий.
- Блочная обработка: Разделяйте данные на части и обрабатывайте их по-отдельности.
- Избегание нецелесообразных вычислений: Не выполняйте операции, не влияющие на конечный результат.
Сохранение последовательности результатов: Всё в порядке
Используя Array.map
и await
с массивом промисов, вы получите результаты строго в том порядке, в котором они были инициированы:
const ids = [1, 2, 3]; // Исходная последовательность идентификаторов
const fetchDataForId = async id => { /* Подготовка важных данных */ };
const dataInOrder = await Promise.all(ids.map(fetchDataForId));
Даже если промисы разрешатся в разное время, dataInOrder
сохранит исходную последовательность ids
.
Полезные материалы
- Array.prototype.map() – JavaScript | MDN — страница MDN, где раскрыты тайны использования async/await с
Array.map
. - Async/await — Детальное руководство от JavaScript Info о async/await, включая их работу с
Array.map
. - JavaScript async and await in loops | Zell Liew — Zell Liew делится знаниями об особенностях использования async/await в циклах, включая
map
. - javascript – Use async await with Array.map – Stack Overflow — Обсуждение на Stack Overflow по теме использования async/await с
Array.map
. - How to use async functions with Array.map in Javascript – Advanced Web Machinery — Введение в последовательное выполнение асинхронных функций с
Array.map
. - Await promise.all: How to use async/await with map and Promise.all – DEV Community — Обзор сообщества разработчиков по использованию асинхронных операций с map.