36
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

mapのループ内でawaitしたいのに怒られてはまった件

Last updated at Posted at 2019-11-22

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内もよく考えたら関数だ:scream::scream::scream:ということに気づく
    • よくわからずに新しい機能を使おうとするからこうなる。よくないね。

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を出力するとこんな感じ

変な配列.PNG

  • 正しい配列はこんなふうになる

正しい配列.PNG

配列ではなくPromiseオブジェクトだった

  • 「変な配列」の正体はPromiseオブジェクトでした!!
    • map内のasyncアロー関数が返しているPromiseのオブジェクトでした
    • コメントを貰って気づきました。ありがとうございます:pray:
  • Promiseオブジェクトを配列として扱おうとして、うまくいっていなかったようです

解決策①:Promise.allを使う

  • Promise.allを使えばmapでまわしたPromiseの結果をかき集めることができます!
    • コメントをもらってこのやり方を知りました。ありがとうございます:pray:
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
}
  • 期待通りの動きになった!!!バンザイ

参考

36
27
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?