我正在设计一个 javascript API,它包装了我的 REST API。我通常希望避免大量冗长且令人困惑的嵌套回调,并且一直在阅读 Deferred jQuery 的优点。
让我们想象一下我的库“myLib”,它代表人物对象以及在人物对象之间遍历的方式。它有一堆方法,如“爸爸”、“老板”、“助理”等,需要执行 ajax 请求来查找一些数据并返回另一个相关的“人”对象。但我希望他们返回一个延迟对象,该对象也具有 myLib 的方法,我可以将它们链接在一起,以编写非常简洁的简单代码,如下所示:
myLib('me').dad().boss().assistant(function(obj){
alert(obj.phone); // My dad's, bosses assistants phone number
}, function(){
alert('No such luck);
});
这会创建一个“我”的人对象,然后执行第一个 ajax 调用来查找我的详细信息,然后使用该数据进行另一个调用来查找我的 parent ,然后再次查找我的老板,然后另一个调用来获取助理,最后传递给我的回调并由我处理。有点像 jQuery 的链式遍历方法,但是是异步的。
在任何点传递一个函数,但通常是最后一个方法,当链中的最后一个 Deferred 对象被解析时,将在内部被调用。第二个函数是失败回调,如果链中的任何延迟对象被拒绝,则调用该函数。
我想我需要创建一个 jQuery 延迟对象,然后扩展它,但不确定这是否是“最佳”方法。
那么实现我的极简 API 目标的最佳实践方法是什么?基本上,我希望所有方法名称 100% 在域问题 namespace 中,并且不会被大量“何时”、“完成”、“成功”等污染。
是否有我可以在某处模拟的类似干净 API 的示例?
最佳答案
我将不理会我的 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 方法时,它确实应该返回一个新的 Person.Chain
,并且该新的Person.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
上的 getter 方法一样多的包装方法。现在,实现管道
:
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
处理程序(如果有)附加到它。然后我们附加一个函数,该函数将调用从前一个函数返回的 Person
上传递的任何 f
(爸爸、助手、老板等)。最后,当该函数解析时,我们显式解析我们创建的 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');
});
如果第一次调用失败,则将按顺序调用两个失败回调。如果只有最后一个失败,则只会调用最后一个。
重要的警告,这些代码都没有经过测试。但是,理论上,这是一种可行的方法。
关于jquery - 使用 jQuery 延迟管道最简洁的方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7859657/