5

Использование async/await с методом Array.map

13

Столкнулся с проблемой при работе с асинхронными функциями в TypeScript. У меня есть следующий код:

var arr = [1, 2, 3, 4, 5];

var results: number[] = await arr.map(async (item): Promise<number> => {
    await callAsynchronousOperation(item);
    return item + 1;
});

Этот код вызывает ошибку компиляции:

TS2322: Type 'Promise<number>[]' is not assignable to type 'number[]'.
Type 'Promise<number>' is not assignable to type 'number'.

Я пытаюсь использовать async/await вместе с Array.map, но не могу понять, как правильно это сделать. Как я могу исправить эту ошибку? Как объединить async/await и Array.map?

4 ответ(ов)

1

Самый простой способ сделать это:

await Promise.all(
    arr.map(async (element) => {
        ....
    })
)

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

0

Вы можете использовать следующий код для итерации по массиву промисов и ожидания их разрешения:

for await (let resolvedPromise of arrayOfPromises) {
  console.log(resolvedPromise);
}

Дополнительную информацию можно найти в документации Mozilla.

Если вы предпочитаете использовать Promise.all(), вы можете рассмотреть вариант с Promise.allSettled(), который предоставляет более эффективный контроль над отклонёнными промисами. Это позволяет обрабатывать результаты всех промисов, независимо от того, были ли они выполнены успешно или нет.

Дополнительную информацию о Promise.allSettled() можно найти в документации Mozilla.

0

Я бы порекомендовал использовать Promise.all, как упоминалось выше, но если вы действительно хотите избежать этого подхода, вы можете использовать цикл for или любой другой цикл:

const arr = [1,2,3,4,5];
let resultingArr = [];
for (let i in arr) {
  await callAsynchronousOperation(i);
  resultingArr.push(i + 1);
}

Для вашего сведения: Если вы хотите проходить по элементам массива, а не по его индексам (как отметил @ralfoide в комментарии), используйте of вместо in в операторе let i in arr. Так будет правильнее:

for (let i of arr) {
  await callAsynchronousOperation(i);
  resultingArr.push(i + 1);
}
0

Вы можете реализовать задачу на стороне бэкенда следующим образом. Вам нужно получить все сущности из репозитория, добавить новое свойство url и вернуть результат на слой контроллера. Вот пример кода, который демонстрирует, как это можно сделать (благодаря ответу Ajedi32):

async findAll(): Promise<ImageResponse[]> {
    const images = await this.imageRepository.find(); // Это массив типа Image (сущность из базы данных)
    const host = this.request.get('host');
    const mappedImages = await Promise.all(images.map(image => ({...image, url: `http://${host}/images/${image.id}`}))); // Это массив типа Object
    return plainToClass(ImageResponse, mappedImages); // Результат - массив типа ImageResponse
}

Примечание: Сущность Image не имеет свойства url, но ImageResponse - да.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь