Personの実装はほとんどその目的を果たしていると思うので、そのままにしておきます。
function Person(o) {
this.id = o.id;
this.name = o.name;
}
Person.prototype.dad = function(done, fail) {
var promise = $.getJSON('/people/' + this.id + '/dad').pipe(Person, null);
promise.then(done, fail);
return new Person.Chain(promise);
};
Person.prototype.boss = function(done, fail) {
var promise = $.getJSON('/people/' + this.id + '/boss').pipe(Person, null);
promise.then(done, fail);
return new Person.Chain(promise);
};
実装には2つの問題がありPerson.Chain
ます。getterメソッドを呼び出すたびに、実際にはnewを返す必要がPerson.Chain
あり、そのnewPerson.Chain
を「ネスト」する必要があります。AJAX呼び出しの結果を連鎖させる必要があります。これで両方の問題が解決するはずです。
このアプローチには数行の接着剤が必要なので、最初に何度も複製する必要がないことを確認しましょう。
Person.Chain = function(promise) {
this.promise = promise;
};
Person.Chain.prototype.assistant = function(done, fail) {
return this.pipe('assistant', done, fail);
};
Person.Chain.prototype.dad = function(done, fail) {
return this.pipe('dad', done, fail);
};
Person.Chain.prototype.boss = function(done, fail) {
return this.pipe('boss', done, fail);
};
にgetterメソッドがあるのと同じ数のこれらのラッパーメソッドを定義する必要がありますPerson
。さて、実装するにはpipe
:
Person.Chain.prototype.pipe = function(f, done, fail) {
var defer = new $.Deferred();
defer.then(done, fail);
this.promise.pipe(function(person) {
person[f](function(person) {
defer.resolve(person);
}, function() {
defer.reject();
});
}, function() {
defer.reject();
});
return new Person.Chain(defer.promise());
}
まず、新しいDeferredオブジェクトを明示的に作成し、それにハンドラー(存在する場合)をアタッチしdone
ますfail
。次に、前の関数から返されるものf
に渡されたもの(お父さん、アシスタント、上司など)を呼び出す関数をアタッチします。Person
最後に、その関数が解決されると、作成したDeferredオブジェクトを明示的に解決します。これで、次のように連続する呼び出しを連鎖させることができます。
jake = new Person({id: 3, name: 'Jake'});
jake.dad().boss().assistant(function(person) {
alert("Jake's dad's boss's assistant is " + person.name);
});
失敗の処理は一種の冗長であることに注意してください。ただし、一連の呼び出しをチェーン化した場合でも、初期の失敗によってreject()
、最後に指定された失敗のコールバックまで呼び出しが渡されるようにする必要があります。
これを行うことも完全に合法です。
jake.dad(function(person) {
alert('Dad is ' + person.name);
}, function() {
alert('Dad call failed');
}).boss(function(person) {
alert('Jake dad boss is ' + person.name);
}, function() {
alert('One of the calls failed');
});
最初の呼び出しが失敗した場合、両方の失敗コールバックが順番に呼び出されます。最後の1つだけが失敗した場合、その1つだけが呼び出されます。
大きな注意点ですが、このコードはどれもテストされていません。しかし、理論的には、これは実用的なアプローチです。