Async/Await inside Array#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
}
});
};
6 ответов
Вы не можете сделать это так, как вы себе представляете, потому что вы не можете использовать await
если это не непосредственно внутри async
функция.
Здесь разумно было бы сделать так, чтобы функция передавалась map
асинхронный. Это означает, что map
вернул бы массив обещаний. Затем мы можем использовать Promise.all
чтобы получить результат, когда все обещания вернутся. Как 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);
}
Если вы хотите запустить карту с функцией асинхронного сопоставления, вы можете использовать следующий код:
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
. Нам нужно дождаться разрешения всех асинхронных функций, прежде чем станет доступен результат.
Я считаю, что это потому, что функция в map
не асинхронный, так что вы не можете ждать в его операторе возврата. Компилируется с этой модификацией:
const someFunction = async (myArray) => {
return myArray.map(async (myValue) => { // <-- note the `async` on this line
return {
id: "my_id",
myValue: await service.getByValue(myValue)
}
});
};
Так что... невозможно дать рекомендацию, не видя остальную часть вашего приложения, но в зависимости от того, что вы пытаетесь сделать, либо сделайте внутреннюю функцию асинхронной, либо попробуйте придумать другую архитектуру для этого блока.
Обновление: мы могли бы получить на высшем уровне ждать один день: https://github.com/MylesBorins/proposal-top-level-await
это будет 2 инструкции, но просто сдвиньте "ожидание" с дополнительной инструкцией
let results = array.map((e) => fetch('....'))
results = await Promise.all(results)
Я пробовал все эти ответы, но в моем случае никто не работает, потому что все ответы возвращают
promise
объект не
result of the promise
нравится:
{
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: Array(3)
0: ...an object data here...
1: ...an object data here...
2: ...an object data here...
length: 3
[[Prototype]]: Array(0)
}
Затем я нашел этот ответ /questions/56210095/karta-async-await-ne-ozhidaet-zaversheniya-funktsii-async-vnutri-funktsii-kartyi/56210104#56210104 котором указано, не является ли функция асинхронной или обещанной. Поэтому вместо использования внутри
map
функция, я использую цикл и
await
отдельный пункт, потому что он сказал, что
for
петля
async
осведомлен и приостановит цикл.
Если вы хотите, чтобы каждое переназначенное значение было разрешено перед переходом к следующему, вы можете обработать массив как асинхронную итерацию.
Ниже мы используем библиотеку iter-ops, чтобы преобразовать каждое значение в обещание, а затем создать объект с разрешенным значением, потому что
map
сам по себе не должен обрабатывать какие-либо обещания внутри.
import {pipe, map, wait, toAsync} from 'iter-ops';
const i = pipe(
toAsync(myArray), // make asynchronous
map(myValue => {
return service.getByValue(myValue).then(a => ({id: 'my_id', myValue: a}))
}),
wait() // wait for each promise
);
(async function() {
for await (const a of i) {
console.log(a); // print resulting objects
}
})
После каждого значения мы используем ожидание для разрешения каждого переназначенного значения по мере его создания, чтобы требование разрешения соответствовало исходному вопросу.