Async/Ожидание внутри массива # map()

Я получаю ошибку времени компиляции с помощью этого кода:

const someFunction = async (myArray) => {
    return myArray.map(myValue => {
        return {
            id: "my_id",
            myValue: await service.getByValue(myValue);
        }
    });
};

Сообщение об ошибке:

Ожидание - это зарезервированное слово

Почему я не могу использовать его так?

Я также пробовал другой путь, но он дает мне такую ​​же ошибку:

 const someFunction = async (myArray) => {
    return myArray.map(myValue => {
        const myNewValue = await service.getByValue(myValue);
        return {
            id: "my_id",
            myValue: myNewValue 
        }
    });
};

Ответ 1

Вы не можете сделать это, как вы себе представляете, потому что вы не можете использовать await, если он не находится непосредственно внутри функции async.

Разумной задачей здесь было бы сделать функцию, переданную в map асинхронной. Это означает, что map вернет массив из promises. Затем мы можем использовать Promise.all для получения результата, когда возвращается все promises. Поскольку Promise.all сам возвращает обещание, внешняя функция не должна быть async.

const someFunction = (myArray) => {
    const promises = myArray.map(async (myValue) => {
        return {
            id: "my_id",
            myValue: await service.getByValue(myValue)
        }
    });
    return Promise.all(promises);
}

Ответ 2

Это потому, что функция в map не является асинхронной, поэтому вы не можете ожидать в ней оператора return. Компилируется с этой модификацией:

const someFunction = async (myArray) => {
    return myArray.map(async (myValue) => { // <-- note the 'async' on this line
        return {
            id: "my_id",
            myValue: await service.getByValue(myValue)
        }
    });
};

Попробуйте в Babel REPL

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

Обновление: мы могли бы получить на высшем уровне ждать один день: https://github.com/MylesBorins/proposal-top-level-await

Ответ 3

Если вы хотите запустить карту с функцией асинхронного отображения, вы можете использовать следующий код:

const resultArray = await Promise.all(inputArray.map(async (i) => someAsyncFunction(i)));

Как это работает:

  • inputArray.map(async ...) возвращает массив обещаний - по одному для каждого значения в inputArray.
  • Помещение Promise.all() вокруг массива обещаний превращает его в одно обещание.
  • Одно обещание из Promise.all() возвращает массив значений - каждое обещание каждого разрешения принимает одно значение.
  • Мы помещаем await перед Promise.all(), чтобы дождаться разрешения объединенного обещания и сохранить массив разрешенных вложенных обещаний в переменную resultArray.

В конце мы получаем одно выходное значение в resultArray для каждого элемента в inputArray, сопоставленное через функцию someAsyncFunction. Нам нужно дождаться разрешения всех асинхронных функций, прежде чем станет доступен результат.