jquery - 使用 jQuery 延迟管道的最简洁方法是什么?

原文 标签 jquery jquery-deferred deferred

我正在设计一个 javascript API,它包装了我的 REST API。我通常希望避免大量冗长和困惑的嵌套回调,并且一直在阅读延迟 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 目标的最佳实践方法是什么?基本上,我希望所有方法名称在域问题 namespace 中都是 100%,并且不会被大量“何时”、“完成”、“成功”等污染。

是否有我可以在某处模拟的类似干净 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 方法一样多的这些包装器方法。 .现在,实现 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 对象,并附加 donefail处理程序(如果有)。然后我们附加一个函数来调用任何 fPerson 上通过了(爸爸、助理、老板等)这将从前一个函数返回。最后,当该函数解析时,我们显式解析我们创建的 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/

相关文章:

javascript - 快速滚动时获取scrollTop

javascript - 在页面上为每个iFrame添加`load`事件

javascript - 如何将此延迟样式 promise 转换为 ES6 样式 promise

jquery - Bootstrap 模式关闭后,html5视频继续在后台播放

php - 使用jQuery或PHP检测较深或较浅的背景颜色

javascript - AJAX - 同时运行两个请求,但其中一个以一定的间隔重复

javascript - 为什么 jQuery.then() 在使用 $.deferred 和 $.ajax 时表现不同

jquery - jquery $ .when $ .then问题

javascript - 不是作为 jQuery Deferred 执行的异步函数

javascript - 如何在 Dojo Deferred 解决之前阻止?