Promise ではまったことがあったので、サンプルを動かしつつ学びなおしました。
参考
配列のPromiseを直列で実行する方法
https://zenn.dev/wintyo/articles/2973f15a265581
こちらの実装を元にして応用させていただきました。ありがとうございます。
動作確認
下記環境で行いました。
node -v
v16.5.0
deno -V
deno 1.9.0
コード
const waitTimes = [300, 100, 200, 500, 400];
function wait(waitTime, name) {
return new Promise((resolve) => {
setTimeout(() => {
console.log(`${name} ${waitTime}ms waited.`);
resolve();
}, waitTime);
});
}
(async () => {
console.log('start wait')
await (async () => {
wait(waitTimes[0], 'wait');
wait(waitTimes[1], 'wait');
wait(waitTimes[2], 'wait');
wait(waitTimes[3], 'wait');
wait(waitTimes[4], 'wait');
})();
console.log('end wait')
await wait(2000, 'end wait')
// 単に Promise オブジェクトを生成すると並列に実行され
// end も待機しない
// start wait
// end wait
// wait 100ms waited.
// wait 200ms waited.
// wait 300ms waited.
// wait 400ms waited.
// wait 500ms waited.
console.log('start Promise.all 1')
await (async () => {
await Promise.all([
wait(waitTimes[0], 'Promise.all 1'),
wait(waitTimes[1], 'Promise.all 1'),
wait(waitTimes[2], 'Promise.all 1'),
wait(waitTimes[3], 'Promise.all 1'),
wait(waitTimes[4], 'Promise.all 1'),
]);
})();
console.log('end Promise.all 1')
// Promise.all で並列に実行され、終了も待機することができる
// start Promise.all 1
// Promise.all 1 100ms waited.
// Promise.all 1 200ms waited.
// Promise.all 1 300ms waited.
// Promise.all 1 400ms waited.
// Promise.all 1 500ms waited.
// end Promise.all 1
console.log('start Promise.all 2')
await (async () => {
await Promise.all(
waitTimes.map((waitTime) => {
return wait(waitTime, 'Promise.all 2');
})
);
})();
console.log('end Promise.all 2')
// Promise.all に Promise オブジェクトの配列を渡す場合は
// 並列に実行され、終了も待機することができる
// start Promise.all 2
// Promise.all 2 100ms waited.
// Promise.all 2 200ms waited.
// Promise.all 2 300ms waited.
// Promise.all 2 400ms waited.
// Promise.all 2 500ms waited.
// end Promise.all 2
console.log('start Promise.all 3')
await (async () => {
await Promise.all(
waitTimes.map((waitTime) => {
wait(waitTime, 'Promise.all 3');
})
);
})();
console.log('end Promise.all 3')
await wait(2000, 'end wait')
// Promise.all に Promise オブジェクトの配列を渡さない場合は
// 待機されずに実行されるので、end が先に実行される
// start Promise.all 3
// end Promise.all 3
// Promise.all 3 100ms waited.
// Promise.all 3 200ms waited.
// Promise.all 3 300ms waited.
// Promise.all 3 400ms waited.
// Promise.all 3 500ms waited.
console.log('start Promise.all 4')
await (async () => {
await Promise.all(
waitTimes.map(async (waitTime) => {
await wait(waitTime, 'Promise.all 4');
})
);
})();
console.log('end Promise.all 4')
// Promise.all に async 関数を渡して
// await で待機すると、Promise オブジェクトを渡したのと同じく動作する
// start Promise.all 4
// Promise.all 4 100ms waited.
// Promise.all 4 200ms waited.
// Promise.all 4 300ms waited.
// Promise.all 4 400ms waited.
// Promise.all 4 500ms waited.
// end Promise.all 4
console.log('start Promise.all 5')
await (async () => {
await Promise.all(
waitTimes.map(async (waitTime) => {
wait(waitTime, 'Promise.all 5');
})
);
})();
console.log('end Promise.all 5')
await wait(2000, 'end wait')
// Promise.all にasync関数を渡すが
// async 関数内で await しないと
// 待機されずに実行されるので、end が先に実行される
// start Promise.all 5
// end Promise.all 5
// Promise.all 5 100ms waited.
// Promise.all 5 200ms waited.
// Promise.all 5 300ms waited.
// Promise.all 5 400ms waited.
// Promise.all 5 500ms waited.
console.log('start for await')
await (async () => {
for await (const result of [
wait(waitTimes[0], 'for await'),
wait(waitTimes[1], 'for await'),
wait(waitTimes[2], 'for await'),
wait(waitTimes[3], 'for await'),
wait(waitTimes[4], 'for await'),
]) {}
})();
console.log('end for await')
// for await は並列に実行され、終了も待機することができる
// start for await
// for await 100ms waited.
// for await 200ms waited.
// for await 300ms waited.
// for await 400ms waited.
// for await 500ms waited.
// end for await
console.log('start for() { await }')
await (async () => {
for (const waitTime of waitTimes) {
await wait(waitTime, 'for() { await }');
}
})();
console.log('end for() { await }')
// for 内で await すると、順次実行される
// start for() { await }
// for() { await } 300ms waited.
// for() { await } 100ms waited.
// for() { await } 200ms waited.
// for() { await } 500ms waited.
// for() { await } 400ms waited.
// end for() { await }
console.log('start then callback')
await (() => new Promise(resolve => {
wait(waitTimes[0], 'then callback').then(() => {
wait(waitTimes[1], 'then callback').then(() => {
wait(waitTimes[2], 'then callback').then(() => {
wait(waitTimes[3], 'then callback').then(() => {
wait(waitTimes[4], 'then callback').then(() => {
resolve()
})
})
})
})
})
}))();
console.log('end then callback')
// Promise オブジェクトの then 内で さらに then を呼び出して
// 連続コールバック関数を使うと、順次実行される
// start then callback
// then callback 300ms waited.
// then callback 100ms waited.
// then callback 200ms waited.
// then callback 500ms waited.
// then callback 400ms waited.
// end then callback
console.log('start then mechod chain 1')
await (() => new Promise(resolve => {
wait(waitTimes[0], 'then mechod chain 1')
.then(() => wait(waitTimes[1], 'then mechod chain 1'))
.then(() => wait(waitTimes[2], 'then mechod chain 1'))
.then(() => wait(waitTimes[3], 'then mechod chain 1'))
.then(() => wait(waitTimes[4], 'then mechod chain 1'))
.then(() => {
resolve()
})
}))();
console.log('end then mechod chain 1')
// Promise オブジェクトの then のメソッドチェーンを使って
// then 内で Promise オブジェクトを return すると、順次実行される
// start then mechod chain 1
// then mechod chain 1 300ms waited.
// then mechod chain 1 200ms waited.
// then mechod chain 1 500ms waited.
// then mechod chain 1 400ms waited.
// end then mechod chain 1
console.log('start then mechod chain 2')
await (() => new Promise(resolve => {
wait(waitTimes[0], 'then mechod chain 2')
.then(() => { wait(waitTimes[1], 'then mechod chain 2') } )
.then(() => { wait(waitTimes[2], 'then mechod chain 2') } )
.then(() => { wait(waitTimes[3], 'then mechod chain 2') } )
.then(() => { wait(waitTimes[4], 'then mechod chain 2') } )
.then(() => {
resolve()
})
}))();
console.log('end then mechod chain 2')
await wait(2000, 'end wait')
// Promise オブジェクトの then のメソッドチェーンを使って
// then 内で Promise オブジェクトを return しないと、
// wait(waitTimes[0] だけ待機したあとに end が実行され
// あとは平行実行される
// start then mechod chain 2
// then mechod chain 2 300ms waited.
// end then mechod chain 2
// then mechod chain 2 100ms waited.
// then mechod chain 2 200ms waited.
// then mechod chain 2 400ms waited.
// then mechod chain 2 500ms waited.
console.log('start then mechod chain 3')
await (() => new Promise(resolve => {
wait(waitTimes[0], 'then mechod chain 3')
.then(wait(waitTimes[1], 'then mechod chain 3'))
.then(wait(waitTimes[2], 'then mechod chain 3'))
.then(wait(waitTimes[3], 'then mechod chain 3'))
.then(wait(waitTimes[4], 'then mechod chain 3'))
.then(() => {
resolve()
})
}))();
console.log('end then mechod chain 3')
await wait(2000, 'end wait')
// Promise オブジェクトの then のメソッドチェーンを使って
// then 内で Promise オブジェクトを返す関数を渡すと
// 並行実行され、wait(waitTimes[0] のあとに end が実行される
// start then mechod chain 3
// then mechod chain 3 100ms waited.
// then mechod chain 3 200ms waited.
// then mechod chain 3 300ms waited.
// end then mechod chain 3
// then mechod chain 3 400ms waited.
// then mechod chain 3 500ms waited.
})();
解説
最初にミリ秒を指定する配列を、順番ばらばらに定義しています。
wait 関数で、指定ミリ秒を待機してからログ出力しています。
並列実行、つまり非同期実行する場合は、待機ミリ秒に従って 100,200,300,400,500 の順番で出力されます。
直列実行、つまり、非同期を同期的に実行する順次実行の場合は、配列の定義通り、300, 100, 200, 500, 400 の順に実行されます。
あとは、コード内のコメント参照してください。