LoginSignup
7
3

【初心者向け】【JS・TS】forEachのコールバック関数内の非同期処理は、async/awaitで同期処理化できない

Posted at

最初に

本記事で紹介することは、JSでforEachやmap等のコールバック関数で処理をするメソッドを使い始めたときに、誰もがやらかしてしまいそうになる内容をまとめてみました。

実はこのコードは、最初に「end」と表示される

const squareNum = (num) => new Promise((resolve, reject) => resolve(num*2));

[2].forEach(async(num) => console.log(await squareNum(num)));// 最後に表示される
console.log("end");// 最初に表示される

配列内の2倍値を表示するために、forEachとsquareNum関数を使う。

しかし、非同期処理として動かしたくないため、forEach内のコールバック関数にasync/awaitを使うが、同期処理化されず最初に「end」が表示されて、最後に「4」が表示されます。

またmapやfind等のコールバック関数で処理をするメソッドも同期処理化されません。

じゃあ、どうやって非同期処理を同期処理化させればいいの?

1. 普通にfor文を使う

プライドを捨てて、普通にfor文を使いましょう!!

const squareNum = (num) => new Promise((resolve, reject) => resolve(num*2));

(async () => {
    for (const num of [2]) {
        console.log(await squareNum(num)); // 最初に表示される
    }
    console.log("end"); // 最後に表示される   
})();

2. forEachにもawaitを使う

async関数内部でしか使えない制限がありますが、これも動きます。

const squareNum = (num) => new Promise((resolve, reject) => resolve(num*2));

(async () => {
    await [2].forEach(async (num) => console.log(await squareNum(num))); // 最初に表示される
    console.log("end"); // 最後に表示される
})();

3. ループ処理外で非同期化できないか設計を変更する

JSは表現度が高い言語です。

なので思い切って設計を変更すること一つの手です。

今回の例題であれば、ループ処理をsquareNum関数に移動させました。

そのため、console.log内部にawaitをするだけでちゃんと表示されるようになります。

const squareNum = (nums) => new Promise((resolve, reject) => resolve(nums.map((num) => num * 2)));

(async () => {
    console.log(await squareNum([2]));// 最初に表示される 
    console.log("end"); // 最後に表示される
})()
7
3
3

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
7
3