目次へ戻る


12) Deferred

Deferred は「延期された」「据え置き」などの意味を持ちます。

weblio Deferred

http://ejje.weblio.jp/content/Deferred

Promises/A では以下のように触れられています。

Promises/A

Proposal
Promises itself may include other additional convenience methods as well. For example, one could implement Dojo’s Deferred functions on promises such as addCallback and addBoth.

「利便性のあるメソッドをPromiseオブジェクトに追加してもいいよ、例えばDojoのDeferredみたいなやつ」と軽く触れられているだけなので、実装するかどうかは開発者に委ねられているようです。

Promises/B では仕様として言及されています。

Promises/B

Specification
1. Returns an Object with a “resolve(value)” property function, and a “promise” property.
2. The first time that “resolve(value)” is called, the state of the “promise” advances to “resolved” and all previous and future promises observing the “promise” are resolved.
3. If the “value” is not a promise, the resolved value of the “promise” becomes a reference (“ref”) to the given value. All subsequent calls to resolve must be silently ignored.

実装ライブラリとして先ほど紹介した Q が記載されています。 QDeferred を見れば挙動が確認できるでしょう。

Promise()との比較

まず通常のPromiseオブジェクトを返す処理を見てみましょう。

function usingPromise(){
  return Q.Promise(function(resolve,reject){
    if (func()) {
      resolve(1);
    } else {
      reject(new Error('reason'));
    }
  });
}

同じ事を Deferred で実装すると以下のようになります。

function usingDeferred(){
  var defer = Q.defer();
  if (func()) {
    defer.resolve(1);
  } else {
    defer.reject(new Error('reason'));
  }
  return defer.promise;
}

コンソールに出力するとどちらもPromiseオブジェクトを返却する事が分かります。

console.log(usingPromise());
console.log(usingDeferred());

plunker

Promiseオブジェクトを返却するため、今までと同じようにthen()による処理を書く事ができます。

usingDeferred()
  .then(function(value){
    throw new Error('abort');
  })
  .catch(function(error){
    console.error(error.message);
  })
;

Deferredとは

では Deferred とは一体何なのでしょうか?console.log(Q.defer())してみると以下のプロパティを持っている事が分かります。

  • fulfill: function
  • notify: function
  • promise: object
  • reject: function
  • resolve: function

この結果を見ると内部にPromiseオブジェクトを持ち、状態を fulfilled または rejected に変化させるオブジェクトだという事が分かります。Promiseオブジェクトの内部(コンストラクタ関数)で状態を変化させるのでなく、外から変化させるためのオブジェクトとして存在しているようです。

また外部のライブラリを使用する場合、ライブラリ独自に拡張されたPromiseオブジェクトが返却される可能性もあります。Promise.resolve()などのStatic Methodでラップして CommonJS で定義された Thenable に変換する事ができますが、Deferredを使った場合も同じように Thenable が保証されます。

さらに Deferred を使うことによりcallbackを使ったアプローチから解放されるメリットがあります。

参考リンク

コンストラクタ関数と Deferred の返すPromiseオブジェクトは等価です。そのため私自身は Deferred 導入のメリットが見出だせず、いろいろなサイトで説明を読んで解釈した事をこのページに掲載しました。下記ページに ThenableThenable Promise Manager などについてまとめられていますので興味のある方は参考にしてください。

kriskowal/uncommonjs

https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md


前のページ 次のページ