mapのループ内でawaitしたいのに怒られてはまった件
ループ内でawaitしたかったけど怒られた
- ループ内で非同期関数が返す結果をawaitで受け取ってまとめて返したかった
let ids = [0,1,2]
const getDataByIds = async (ids) => {
let ret = [];
ids.map((id) =>
{
// getDataByIdはasync関数
let data = await getDataById(id)
ret.push(data)
})
return ret
}
- しかし怒られる
Parsing error: Can not use keyword 'await' outside an async function
- 訳:awaitはasync関数以外で使ってんじゃねーぞコラ
- わたし:は?いやいやいやgetDataByIdsはasyncにしてるやん????頭おかしくなったか????アァン
- エラーメッセージでぐぐってもasync関数で囲えやみたいな記事しかない。。。いや囲ってるんですけど…
原因①:map内も関数だった
- async awaitとかPromiseとかをもう一回おさらいしたりぐぐったりしていろいろ考えた結果…
- forのかわりに使ってたので忘れてたけどmap内もよく考えたら関数だということに気づく
- よくわからずに新しい機能を使おうとするからこうなる。よくないね。
map内のアロー関数にasyncつけたらエラーが消えた!!!けど…?
let ids = [0,1,2]
const getDataByIds = async (ids) => {
let ret = [];
// map内のアロー関数にasyncつけたらエラー消えた
ids.map(async (id) =>
{
// getDataByIdはasync関数
let data = await getDataById(id)
ret.push(data)
})
return ret
}
- エラーは消えた!!ばんざい
- ただし結果は期待する挙動にはならなかった。。。。
- 変な配列が返却されちゃう
- 空の配列のようで中身が入っている、でもmap使えない…みたいな謎配列
- console.logでretを出力するとこんな感じ
- 正しい配列はこんなふうになる
配列ではなくPromiseオブジェクトだった
- 「変な配列」の正体はPromiseオブジェクトでした!!
- map内のasyncアロー関数が返しているPromiseのオブジェクトでした
- コメントを貰って気づきました。ありがとうございます
- Promiseオブジェクトを配列として扱おうとして、うまくいっていなかったようです
解決策①:Promise.allを使う
- Promise.allを使えばmapでまわしたPromiseの結果をかき集めることができます!
- コメントをもらってこのやり方を知りました。ありがとうございます
const getDataByIds = async (ids) => {
// 未解決の Promise を集めてしまう。
let promises = ids.map(id => {
return getDataById(id);
});
// Promise.all でまとめて待つ
let ret = await Promise.all(promises);
return ret
}
Promise.all() - JavaScript | MDN
解決策②:mapじゃなくてforつかう
- ちょっとダサいですが、forを使ってもできます!
let ids = [0,1,2]
const getDataByIds = async (ids) => {
let ret = [];
// おとなしくfor使う
for (let i = 0; i < odaiIds.length; i++)
{
// getDataByIdはasync関数
let data = await getDataById(ids[i])
ret.push(data)
})
return ret
}
- 期待通りの動きになった!!!バンザイ
参考
- asyncとかawaitとかについては以下の記事がめちゃくちゃ参考になりました!!!