JavaScript(ES6)のPromiseを試してみる その2

こんにちは、元岡です。 前回に引き続きPromiseの方をご紹介します。

今回はPromiseでラップした非同期処理を、直列に順次処理してみます。

まずはPromiseを使わないで、非同期処理をコールバックで繋げていくと・・・

var async = function(callback){  
   console.log("async start");
   setTimeout(function(){
      console.log("async end");
      if (callback) callback();
   }, 3000);
};

async(function(){  
   async(function(){
      async(function(){
         async(function(){
            async(function(){
               async();
            });
         });
      });
   });
});

実行結果

async start  
async end  
async start  
async end  
async start  
async end  
async start  
async end  
async start  
async end  
async start  
async end  

コールバックのネストがすごいことになってますね。。 エラーのハンドリングや分岐が入ってくると、可読性はさらに悪くなります。

これが コールバック地獄 というやつですね。

では、これをPromiseに置き換えてみましょう。 今回もJQueryDeferredでも描いてみます。

Promiseの場合

var async = function() {  
   return new Promise(function(resolve, reject){
      console.log("async start");
      setTimeout(function(){
        console.log("async end");
        resolve();
      }, 3000);
   })
};

async().then(function(){  
   return async();
}).then(function(){
   return async(); 
}).then(function(){
   return async(); 
}).then(function(){
   return async(); 
}).then(function(){
   return async(); 
});

Deferredの場合

var async = function(){  
   var deferred = new $.Deferred();
   console.log("async start");
   setTimeout(function(){
      console.log("async end");
      deferred.resolve();
   }, 3000);
   return deferred.promise();
};

async().then(function(){  
   return async();
}).then(function(){
   return async(); 
}).then(function(){
   return async(); 
}).then(function(){
   return async(); 
}).then(function(){
   return async(); 
});

処理結果

async start  
async end  
async start  
async end  
async start  
async end  
async start  
async end  
async start  
async end  
async start  
async end  

連続した非同期処理でネストの山になる事なく記述することが出来ますね。 このようにPromiseで非同期処理を繋げることができます。

非同期処理だけでなく、同期処理も絡めたらどうるでしょう。

var sync = function(){  
   return "##sync";
};

async().then(function(){  
   return sync();
}).then(function(label){
   console.log(label);
   return async();
});

処理結果

async start  
async end  
##sync
async start  
async end  

同じように同期処理も繋げることができてますね。

着目していたのは2番目の同期処理の箇所です。 Promiseオブジェクトを返していませんがthenメソッドを呼べていますよね? これはthenメソッドが、Promiseオブジェクト以外のオブジェクトやプリミティブデータが戻り値の時に、自動的にPromiseをラップしてくれて、さらにresolveメソッドで戻り値を返してくれます。

これは非常に親切で便利な機能ですね!

これで複数の処理を綺麗に書くことが出来ましたね。

でも、1つ気になることがあります。 1つめの処理と2つめ移行の処理のインデントがずれてます。 なんだか気持ち悪いですよね。。

これも描きなおしてみます。

Promiseの場合

Promise.resolve().then(function(){

   //処理1
   return async();

}).then(function(){

   //処理2
   return sync();

}).then(function(){

   //処理3
   return async();

});

Deferredの場合

$.when().then(function(){

   //処理1
   return async();

}).then(function(){

   //処理2
   return sync();

}).then(function(){

   //処理3
   return async();

});   

コメントも書き足せば、さらにスッキリ読みやすくなりました!

いかがだったでしょうか? 次回もまた引き続きPromiseを使って、今度は並列処理も行ってみます。

それではまた!