【TypeScript】ループ時の非同期処理の処理順序(async/await)同期化

TypeScript

1. 概要

ループ時の非同期処理の処理順序について書きます。

  • map()
    • 意図した処理順序とならない。
    • Array.prototype.map() – JavaScript | MDN (mozilla.org)
      • map() は Array インスタンスのメソッドで、与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成します。
      • map は新しい配列を作成するので、返された配列を使わない場合、map を使うのはパターンに合いません。代わりに forEach または for…of を使用してください。
  • Promise.all() + map()
  • for…of

2. map()

2-1. ソースコード

type Person = {
    name: string,
    age: number,
}

const members: Person[] = [
    {name: 'John', age: 22},
    {name: 'Smith', age: 33},
    {name: 'Tom', age: 44},
];

const sleep = async (duration: number): Promise<void> => {
    return new Promise<void>((resolve) => {
        setTimeout(resolve, duration);
    });
}

const getHms = () => {
    const date: Date = new Date();
    return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}:${String(date.getSeconds()).padStart(2, '0')}`;
}

const main = async () => {
    console.log(`[${getHms()}] START`);

    const hello = async (person: Person): Promise<string> => {
        await sleep(3000);
        return `Hello, ${person.name} (${person.age})`;
    }

    const run = async (): Promise<void> => {
        console.log(`[${getHms()}] Inside run()`);
        members.map(async (person: Person) => {
            const result: string = await hello(person);
            console.log(`[${getHms()}] (Running) ${result}`);
        });
        console.log(`[${getHms()}] Out of run()`);
    }
    console.log(`[${getHms()}] Before run()`);
    await run();
    console.log(`[${getHms()}] After run()`);

    console.log(`[${getHms()}] END`);
}

main().catch((e) => {
    console.error(e);
});

2-2. 結果

[19:27:45] START
[19:27:45] Before run()
[19:27:45] Inside run()
[19:27:45] Out of run()
[19:27:45] After run()
[19:27:45] END
[19:27:48] (Running) Hello, John (22)
[19:27:48] (Running) Hello, Smith (33)
[19:27:48] (Running) Hello, Tom (44)
  • 処理が最後まで先に走り、非同期処理が指定の3秒後に実行される

3. Promise.all() + map()

3-1. ソースコード

type Person = {
    name: string,
    age: number,
}

const members: Person[] = [
    {name: 'John', age: 22},
    {name: 'Smith', age: 33},
    {name: 'Tom', age: 44},
];

const sleep = async (duration: number): Promise<void> => {
    return new Promise<void>((resolve) => {
        setTimeout(resolve, duration);
    });
}

const getHms = () => {
    const date: Date = new Date();
    return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}:${String(date.getSeconds()).padStart(2, '0')}`;
}

const main = async () => {
    console.log(`[${getHms()}] START`);

    const hello = async (person: Person): Promise<string> => {
        await sleep(3000);
        return `Hello, ${person.name} (${person.age})`;
    }

    const run = async (): Promise<void> => {
        console.log(`[${getHms()}] Inside run()`);
        const results: Promise<string>[] = members.map(async (person: Person) => {
            const result: string = await hello(person);
            console.log(`[${getHms()}] (Running) ${result}`);
            return result;
        });
        await Promise.all(results);
        console.log(`[${getHms()}] Out of run()`);
    }
    console.log(`[${getHms()}] Before run()`);
    await run();
    console.log(`[${getHms()}] After run()`);

    console.log(`[${getHms()}] END`);
}

main().catch((e) => {
    console.error(e);
});

3-2. 結果

[19:32:20] START
[19:32:20] Before run()
[19:32:20] Inside run()
[19:32:23] (Running) Hello, John (22)
[19:32:23] (Running) Hello, Smith (33)
[19:32:23] (Running) Hello, Tom (44)
[19:32:23] Out of run()
[19:32:23] After run()
[19:32:23] END
  • 非同期処理が並列で実行される

4. for…of

4-1. ソースコード

type Person = {
    name: string,
    age: number,
}

const members: Person[] = [
    {name: 'John', age: 22},
    {name: 'Smith', age: 33},
    {name: 'Tom', age: 44},
];

const sleep = async (duration: number): Promise<void> => {
    return new Promise<void>((resolve) => {
        setTimeout(resolve, duration);
    });
}

const getHms = () => {
    const date: Date = new Date();
    return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}:${String(date.getSeconds()).padStart(2, '0')}`;
}

const main = async () => {
    console.log(`[${getHms()}] START`);

    const hello = async (person: Person): Promise<string> => {
        await sleep(3000);
        return `Hello, ${person.name} (${person.age})`;
    }

    const run = async (): Promise<void> => {
        console.log(`[${getHms()}] Inside run()`);
        for (const person of members) {
            const result: string = await hello(person);
            console.log(`[${getHms()}] (Running) ${result}`);
        }
        console.log(`[${getHms()}] Out of run()`);
    }
    console.log(`[${getHms()}] Before run()`);
    await run();
    console.log(`[${getHms()}] After run()`);

    console.log(`[${getHms()}] END`);
}

main().catch((e) => {
    console.error(e);
});

4-2. 結果

[19:35:15] START
[19:35:15] Before run()
[19:35:15] Inside run()
[19:35:18] (Running) Hello, John (22)
[19:35:21] (Running) Hello, Smith (33)
[19:35:24] (Running) Hello, Tom (44)
[19:35:24] Out of run()
[19:35:24] After run()
[19:35:24] END
  • ループ内で、指定した3秒後に同期処理される

5. 備考

ただ動作確認のためにmap()でループ処理を書いてハマったので記事にしてみました。

6. 参考

関連記事

  1. 【React】FullCalendarのカレンダーを整えるためのTip…

  2. 【React】FullCalendarのカレンダーにイベントを表示する…

  3. 【React】FullCalendarを使用してカレンダーを表示するた…

  4. Firebase

    【Firebase】Firestore Security Rulesを…

  5. 【React】FullCalendarのヘッダーツールバーを整えるため…

  6. TypeScript

    【TypeScript】Vitestを使ってみる

最近の記事

  1. PHP
  2. PHP
  3. TypeScript
  4. Docker

制作実績一覧

  1. Checkeys