JavaScript #11 Promise

2020年12月12日

Promiseって何に使うの

Promiseとは、ES6で実装されたJavaScriptにおける非同期処理の操作が完了したときの状態によって、処理を行う仕組みのことをPromiseと言います。
なにそれ?って感じですが、JavaScriptでよくある使い方は、Webサーバにリクエストを投げて、その結果に対して処理を行う場合などに使います。
例外処理のでは、例外が発生する可能性のある処理(失敗するかもしれない処理)にはあらかじめ例外(失敗したときの動作)を定義して処理のリカバリーなどを行う用途に使うものでした。
Promiseも似ていて、判定したい非同期処理の事象の結果を待ち、結果が成功した場合、失敗した場合を定義して、次の処理に分岐していくものです。
Webサーバの例で例えると、Webサーバにリクエストを投げます。投げたリクエストが正常に応答が帰ってくれば正常処理(Webサーバから取得したデータを元に処理をする。)を行い、Webサーバから応答がない場合やエラーの応答がある場合には、例外処理(エラー通知を行う。)ような処理のハンドリングを行う目的で利用することが多いものです。

Promiseの使い方

Promiseの使い方に関してまとめていきたいと思います。Promiseは処理の状態を管理し、その処理結果に応じた処理制御をおこなうため、Promiseは以下の3つの状態で遷移します。詳しくは公式サイトを見て。

状態説明
初期状態(pending)未処理の状態、成功、失敗の結果が起きる前の状態
満足(fulfilled処理が成功した場合の状態
拒絶(rejected)処理が失敗した場合の状態


Promiseは以下のような書き方で使います。まずPromiseはオブジェクトのためnewで宣言し、内容はコールバック関数で中身を記述します。また、引数に与えます。処理が成功した場合(fulfilled)と処理がエラーになった場合(rejectred)を指定します。引数はかならずしも成功・失敗を与える必要はないです。成功だけでもOKです。引数名は例示だとfulfilled、rejectedとなっていますが、他の引数名でも問題ないです。
アロー関数内に状態に応じた処理を記述し、状態を返す形で記述すればOKです。
下の例では、変数numの値に応じて、numが1だったらPromiseは成功し、それ以外だったら失敗した処理を実行してくれます。


  function test(check){
    return new Promise((fulfilled,rejected)=>{
      if(check !== 1){
        rejected('プロミスの生成に失敗しました');
      }else{
        fulfilled("プロミスの生成に成功しました");
      }
    });
  }

  let num = 1;
  console.log(test(num));

上記のロジックでは、変数numの値を1以外にセットすると、関数test内のPromiseで、1以外は失敗(rejectted)を返すため、例外が発生し、コンソールに「Uncaught (in promise)」と表示されます。

例外を捕まえる

それではどのようにしたら良いかというと、例外処理と同じように例外発生時の例外を捕まえる(catch句)をつけて見たいと思います。例えばこんな感じ。下記を実行すると、例外エラーはきちんと捕まえることができて、なおかつ、例外処理も動かすことができます。書き方はメソッドチェーンのように、関数の後ろにcatch句を記述すればよいのです。

  function test(check){
    return new Promise((fulfilled,rejected)=>{
      if(check !== 1){
        rejected('プロミスの生成に失敗しました');
      }else{
        fulfilled("プロミスの生成に成功しました");
      }
    });
  }

  let num = 2;
  console.log(test(num).catch((e)=>{
      console.log('例外を見つけました。'+e);
    }));

Promiseチェーン

先程は、例外が発生したときはメソッドチェーンのように例外を記述すれば良いとしましたが、メソッドチェーン同様にエラーではない場合に次の処理を書くこともできます。例えばこんなかんじ。

  function test(check){
    return new Promise((fulfilled,rejected)=>{
      if(check !== 1){
        rejected('プロミスの生成に失敗しました');
      }else{
        fulfilled("プロミスの生成に成功しました");
      }
    });
  }

  let num = 1;
  console.log(test(num)
    .then((num)=>{
      console.log("次に進む");
    })
    .catch((e)=>{
      console.log('例外を見つけました。'+e);
    }));

上記例では、変数numの値が1だった場合は、次の処理(then句)の処理を実行します。変数numの値が1以外だったら、例外処理(catch句)が実行されます。
このメソッドチェーンのような書き方をPromiseを使って構成することをPromiseチェーンと呼びます。Promiseチェーンは、非同期処理において、Aを実行してOKならBを実行し、さらにOKならCを実行するような処理ができ、それぞれ例外が発生したら、そこで例外処理を行うようなものができます。

実はPromiseを使わなくても、コールバック関数だけでも実現できるじゃんなんでPromiseなんかできたの?と思われると思いますが、実際にコールバック関数だけで記述していくと、処理の度にコールバック関数をひたすら入れ子(ネスト)して書かねばならず、非常に読みにくくメンテナンスしづらい、コールバック地獄と呼ばれるコードになってしまうため、ES6を使って記述する場合はPromiseを利用することでスッキリ書くことができるようになりました。

簡単ですがPromiseについてまとめてみました。

Program

Posted by Qtaro