我将不理会我的 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);
};
对于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);
};
我们只需要定义尽可能多的这些包装器方法,就像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');
});
如果第一次调用失败,将按顺序调用两个失败回调。如果只有最后一个失败,则只会调用那个。
大警告,这些代码都没有经过测试。但是,从理论上讲,这是一种可行的方法。