Deferred/Promise

jQuery には非同期処理を扱うための Deferred というモジュールが用意されています。

非同期処理が複数連結されるようなケースでは、いわゆるコールバック地獄と呼ばれるコーディングが必要となりますが、Deferred を利用することでシンプルに記述することが可能です。

前章で学んだ $.get$.post$.ajax は実はこの Deferred が利用されています。

利用方法

Deferred#promise を実行すると Promise オブジェクトを返却します。 呼び出し側はこの Promise オブジェクトに処理成功・失敗時に実行したい関数を登録します。

非同期処理が完了したら Deferred#resolveDeferred#reject を実行すると、Promise オブジェクトの状態が変化し、登録されていたコールバック関数が呼び出される、という仕組みです。

var callAsync = function() {
  var deferred = $.Deferred();

  // setTimeout で非同期処理をエミュレート
  // 実際には $.ajax などの処理を行う
  setTimeout(function() {
    if (Math.random() > 0.5) {
      // 非同期処理を成功扱いとする
      deferred.resolve();
    } else {
      // 非同期処理を失敗扱いとする
      deferred.reject();
    }
  }, 1000);

  // Promise オブジェクトを返却 = 非同期処理の結果を返すことを約束する.
  return deferred.promise();
}

callAsync()
  .then(function() {
    console.log('処理完了時に実行');
  })
  .done(function() {
    console.log('処理成功時のみ実行');
  })
  .fail(function() {
    console.log('処理失敗時のみ実行');
  })
  .always(function() {
    console.log('常に実行');
  });

Deferred/Promise の関係については、以下のサイトを参照してください。

直列実行

非同期処理を直列実行する場合、Deferred を利用しないとコールバック処理がネストしてしまいます。 このようなコーディングをコールバック地獄と呼びます。

var callAsync = function(callback) {
  setTimeout(function() {
    callback.call(this);
  }, 1000);
};

callAsync(function() {
  console.log('success 1');
  callAsync(function() {
    console.log('success 2');
    callAsync(function() {
      console.log('success 3');
    });
  });
});

Deferred を利用すると以下のように記述することができます。

var callAsync = function(callback) {
  var deferred = $.Deferred();

  setTimeout(function() {
    deferred.resolve();
  }, 1000);

  return deferred;
};

callAsync()
  .then(function() {
    console.log('success1');
    return callAsync();
  })
  .then(function() {
    console.log('success2');
    return callAsync();
  })
  .then(function() {
    console.log('success3');
  });

並列実行

$.when を利用すると、非同期処理を並列実行することが可能です。

var callAsync = function(callback) {
  var deferred = $.Deferred();

  setTimeout(function() {
    console.log('success');
    deferred.resolve();
  }, 1000);

  return deferred;
};

$.when(
  callAsync(),
  callAsync()
).done(function() {
  console.log('end');
});

results matching ""

    No results matching ""