バンビのブログ

駆け出しのエンジニアです!日々の疑問など備忘録として書いていきます。

Promiseとは その1

Promise:
【第一弾 Promiseとは】あとでPromise.allなど非同期処理を並列で行うこととか別で書きます。

【async/awaitは更にPromiseを可読性よく書くようにしたもの】ですのでそのもとを知るとわかりやすいとおもいました!

まずJSには同期処理と非同期処理があります。

・同期処理とは、上から順番に処理を実行していくことです。
関数A(同期処理)
 ↓
関数B(同期処理)
 ↓
関数C(同期処理)
だけどこの一連の処理が完了させる場合、「関数B」の処理がクソ重くて動かなかった場合、「関数C」はただただぼけーーーっと関数Cの順番がくるのを待っているだけで何も実行されない。
これが同期処理です。


・非同期処理とは、上から順番に処理を実行しつつ非同期処理に結果が返ってくるのを待たずに次の処理を実行するという仕組み。
A関数(同期処理)
 ↓
B関数(非同期処理)
 ↓
C関数(同期処理)
「B関数」の処理がクソ重くても非同期処理にしてあるから、先にC関数実行していいよという流れです。


・非同期処理の結果が返ってきたあとどうするのか。

関数A(日付データを取得する)
↓
関数B(日付データから西暦を抽出する)
 //関数A 日付データを取得する
 function getDate() {
     var date = new Date;
 }

 //関数B 日付データを元に西暦を取得する
 function getYear(data) {
   var year = data.getFullYear();
 }

日付データ取得後に、取得したデータをもとにgetYear()(西暦を計算する関数)を実行。なので日付データ取得がうまくいかないとgetYear()は実行できない状態です。
なのでこのgetDate()の処理が成功したあとにgetYear()を実行するようにcallbackを使って書き直して見る。

 //getDateの引数にcallback(名前はcallbackでなくてもいい)という関数を引数に受け取れる用に変更してみました。
 function getDate(callback) { 
     callback(new Date); 
 }
 
 //getDateの引数に関数を渡すと下記のように変化します。
 getDate(function(data) { 
 
 //getYear(data)のdataにはcallback(new Date)のnew Dateの値が入ってくる
    getYear(data);  
 });

それならコールバックの連鎖つくれるやんとなって下記のようになる(これはコールバック地獄で処理をおうのが大変でクソコード認定される)
 getDate(function(data1) {
     getYear(function(data2) {
         getSomething(function(data3) {
             getAnotherThing(function(data4) {
                     //何らかの処理をする
             });
         });
     });
 });

このコールバック地獄を解消してくれるのがPromiseです!

PromiseはPromiseオブジェクトを作成して簡潔に非同期処理がかけるというもので、Promiseオブジェクト作成は下記の様に書きます。

・pending(待機中)/resolve(成功時の処理)/reject(失敗時の処理)

//new Promise( )の引数に関数を設定するのが一般的らしい。
 var result = new Promise()//これがプロミスオブジェクトの作成!!
 var result = new Promise(function(resolve, reject) {
     //成功時の下記を実行
     resolve(new Date);
    //失敗時に下記を実行
     reject(new Error('Error'));
 })

このあと非同期処理をおこなうようにするには.thenを使った処理を書きます。

 //function(data)にはresultで返ってきた値が格納されます。
 result.then(function(data){ 

    console.log(data.getFullYear());

  ).catch(function (error) {

    // rejectが実行された場合catchが呼ばれエラーが返される
    console.log(error);  // => 'Error'

  });
}

thenをつなげてかくことによって連鎖(メソッドチェーン)した非同期処理をかくことができる。

//thenは返り値を明確に書いてあげないとだめです。「return 返したいPromiseオブジェクト」を関数内にちゃんと書いてあげましょう。

 function something1() {

  //「return 返したいPromiseオブジェクト」
   return new Promise(function(resolve) {

     setTimeout(function() {

       resolve('なにか処理');

     }, 3000)
   })
 }

//処理をつなげるとこんな風に書きます。
result.then(関数A).then(関数B).then(関数C).catch(function (error) { console.log(error); });

【ES6】だとこんなふうに書きます。
result.then( (data) => console.log(data.getFullYear()) );