2
0

More than 1 year has passed since last update.

[JavaScript] Promiseオブジェクトを順次実行するサンプル

Posted at

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 の順に実行されます。

あとは、コード内のコメント参照してください。

2
0
2

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
2
0