javascript の Promise おぼえがき

AWS lambda で Node.js と向きう合う必要が出てきたので、最近のモダンな JS を理解する

最近は async/await が使えるらしいが、内部的には Promise を使っているらしいので、まずは Promise から理解する

Promise とは?

非同期処理の実行結果(成功 or 失敗) の受け取り口を用意して、非同期の管理を容易にするためのオブジェクト

コールバック地獄のしんどさを回避するために生まれた

つかいかた

new Promise する

  • 第一引数は、引数が2つある関数
    • 関数の第1引数には、正常終了時に呼び出す関数
    • 関数の第2引数には、異常終了時に呼び出す関数
  • new Promise の戻り値は、then()catch() を持つオブジェクト
    • then() には正常終了時に呼ばれる関数を渡す
    • catch() には異常終了時に呼ばれる関数を渡す
      - 例外を勝手に拾ってくれたりはしないので、自前で例外をコントロールする必要がある
      
  • then()catch() が呼ばれた時点で、promise に渡した関数が実行される

正常終了例

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('foo');
  }, 10);
});

promise.then((value) => {
  console.log("then");
  console.log(value);
}).catch((value) => {
  console.log("catch");
  console.log(value);
});

出力結果

then
foo

異常終了例

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('foo');
  }, 10);
});

promise.then((value) => {
  console.log("then");
  console.log(value);
}).catch((value) => {
  console.log("catch");
  console.log(value);
});

出力結果

catch
foo

Promise のチェーン

then() の戻り値を Promise オブジェクトにすることで、Promise をチェーンできる

これにより、非同期処理を同期的に実行できる

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('promise1');
  }, 10);
});

promise1.then((value) => {
  console.log("then 1");

  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('promise2');
    }, 10);
  });

}).then((value) => {
  console.log("then 2");
});

出力結果

then 1
then 2

Promise#all

複数 Promise の並列実行ができる

正常終了例

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('promise1')
    resolve('promise1');
  }, 10);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('promise2')
    resolve('promise2');
  }, 10);
});

Promise.all([
  promise1, promise2
]).then((value) => {
  console.log(value)
  console.log('finished')
});

then() には、各 Promiseresolve の引数を配列にしたものが渡される

promise1
promise2
[ 'promise1', 'promise2' ]
finished

異常終了例

1つでも reject() が呼ばれたら catch() が呼ばれる

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('promise1');
  }, 10);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('promise2');
  }, 10);
});

Promise.all([
  promise1, promise2
]).then((value) => {
  console.log(value)
  console.log('finished')
}).catch((value) => {
  console.log(value)
  console.log('catch')
});

出力結果

promise2
catch

reject() が複数発生する場合も、早いもの勝ちで最初の reject() の引数が渡される 処理自体は最後まで行われる

Promise.race()

複数 Promise のうち、1つでも処理が完了したら then() が呼ばれる