【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. TypeScript

    【TypeScript】Vitestを使ってみる

  2. 【TypeScript】filterを使って配列からundefined…

  3. 【React×TypeScript】環境構築メモ

  4. TypeScript

    【TypeScript】インターフェイスの実装

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

  6. TypeScript

    【TypeScript】触ってみる

最近の記事

  1. PHP
  2. PHP
  3. TypeScript
  4. Docker
  5. AWS
  6. Docker

制作実績一覧

  1. Checkeys