jQuery.Deferredでコールバック地獄から抜け出す

jQuery.Deferredとは

jQueryのバージョン1.5で導入され、コールバックキューの登録・呼び出し、同期・非同期関数の成功・失敗の状態を監視するオブジェクトです。

 

詳しくは最寄りのG◯◯gle検索結果若しくは公式解説ページリンクまで

 

複数の関数を実行する際に、setTimeoutのコールバックを利用することがあると思います。

実行する関数が少ない場合は特に問題にならないと思いますが、関数が増えると厄介なこと(コールバック地獄)になります。

 

実装例のコードを見た方が話が早いと思いますので、コードとデモを用意しました。

(デモページを用意したけど、見た目の違いはほぼ無いです・・・)

 

例では焼そばの材料の準備から盛り付けまでの手順を関数で実行しています。

(焼そばに深い意味はありません・・・)

 

各手順の関数を用意し、関数毎にコンソールとブラウザにテキストを追加で表示しています。

  • 材料を買う・・・gotoShopping
  • 材料切る・・・cutting
  • 材料を炒める・・・frying
  • 味付けする・・・seasoning
  • 盛り付け・・・serveDish

 

setTimeoutの繰り返しでコールバック地獄で乗り切る方法

デモページ

 

コード

※関数の実行箇所のみ抜粋

gotoShopping();
    setTimeout(function() {
      cutting();
      setTimeout(function() {
        frying();
        setTimeout(function() {
          seasoning();
          setTimeout(function() {
            serveDish();
          }, 1000);
        }, 1000);
      }, 1000);
    }, 1000);
  }

見ただけで発狂しそうなコードですね。

 

jQuery.Deferredでコールバック地獄から抜け出す方法

デモページ

 

コード

※関数の実行箇所のみ抜粋

gotoShopping()
    .then(cutting)
    .then(frying)
    .then(seasoning)
    .then(serveDish);

 

上のコードの違いを見ると一目瞭然ですが、jQuery.Deferredを使用した方が圧倒的にコードがシンプルになり、メンテナンスがしやすくなります。

上の例に別の関数を途中で追加したい場合や、順番の入れ替えが発生した場合、setTimeoutでの実装だと階層を深くしたり入れ替えたりする必要があるので、改修が面倒なコードになります。

 

 

jQuery.Deferredを利用した関数の作り方

※今回は通信を使用しないのでresolve(成功)のみ

function gotoShopping() {
    var def = $.Deferred(); //オブジェクト生成
    setTimeout(function() {
      console.log('材料を買う');
      def.resolve(); //コールバックの実行成功
    }, 1000);
    return def.promise(); //実行する関数に返す
  }

 

通信の監視の他にも「アニメーションを実行した後に色を変えたい」といったアニメーションの実行でも流用出来るので大変便利です。