1. 概要
ループ時の非同期処理の処理順序について書きます。
- map()
- 意図した処理順序とならない。
- Array.prototype.map() – JavaScript | MDN (mozilla.org)
- map() は Array インスタンスのメソッドで、与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成します。
- map は新しい配列を作成するので、返された配列を使わない場合、map を使うのはパターンに合いません。代わりに forEach または for…of を使用してください。
- Promise.all() + map()
- 意図した処理順序にはなるが、並列処理となる。
- Promise.all() – JavaScript | MDN (mozilla.org)
- for…of
- 意図した処理順序と直列処理となる。
- for…of – JavaScript | MDN (mozilla.org)
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. 参考
- for…of – JavaScript | MDN (mozilla.org)
- Array.prototype.map() – JavaScript | MDN (mozilla.org)
- Promise.all() – JavaScript | MDN (mozilla.org)
投稿者プロフィール
-
開発好きなシステムエンジニアです。
卓球にハマってます。