【问题标题】:Late binding for jQuery.whenjQuery.when 的后期绑定
【发布时间】:2013-11-29 12:59:48
【问题描述】:

我正在使用一个使用 jQuery Deferred Objects 的框架。

在我的代码中,一个异步操作应该成功执行,以便执行另一个异步操作。

function doOperation() {

    var def2mock = $.Deferred();
    var def1 = doSomeAsyncOperation().done(function () {
        var def2 = doAnotherAsyncOperation();
    });

   return $.when(def1, def2mock);
}

所以我将第二个操作的调用放在第一个操作的延迟的“完成”承诺中,如示例中所示。 现在,我用函数doOperation 包装这个序列。 doOperation 的结果应该是两个异步调用的两个延迟的连接。意思是 doOperation 如果所有异步操作都成功则成功,如果其中任何一个操作失败则失败,这正是 $.when 所做的。

问题是为了创建与$.when 的连接,我需要在调用$.when 时同时存在两个延迟。并且由于此时第二个异步操作的延迟不可用,我不得不先找到一种方法来创建连接,然后将第二个异步操作的延迟添加到连接中稍后

为此,我想我可以在doOperation 中定义一个名为def2 的新mock $.Deferred。当真正的def2 准备好时,我可以以某种方式链接真正的延迟到模拟的,即使真实的状态与模拟的同步。我发现的唯一方法是做

def2.done(def2mock.resolve)
// and 
def2.fail(def2mock.reject)

但我不认为这种手动链接是正确的方法。

所以请告诉我你是否有更好的建议来正确地做这件事。

【问题讨论】:

  • 其实应该是def2.then(def2mock.resolve,def2mock.reject,def2mock.notify)
  • 下面的人不会这样做吗:return doSomeAsyncOperation().then(doAnotherAsyncOperation()) ?
  • 没有内引号,也许
  • @Noseratio,在对.then 的概念和@FelixKling 的fitlers 有了更好的理解之后,我说你的建议确实有效。谢谢。
  • @HasanBaidoon,没问题。您可能想阅读Q Library 上的文档,它与 jQuery 承诺兼容。我觉得这是一本非常全面的阅读材料。

标签: javascript jquery asynchronous deferred


【解决方案1】:

当真正的def2 准备就绪时,我可以以某种方式链接真正的延迟到模拟的,即使真实的状态与模拟的同步。

这实际上是 .then 所做的:它返回一个新的 Promise,当从传递的回调返回的 Promise 被解析/拒绝时,它会被解析/拒绝。

为了使这个工作与$.when 一起工作,您必须保留对原始承诺的引用:

function doOperation() {
  var def1 = doSomeAsyncOperation();
  var def2 = def1.then(function () {
    return doAnotherAsyncOperation();
  });
  return $.when(def1, def2);
}

DEMO

def2 将在回调返回的 promise 被解析时被解析,即 doAnotherAsyncOperation 返回的那个。


但从概念的角度来看,我不认为在这里使用$.when 是一个好的选择。你实际上是在顺序执行两个异步函数,但是$.when是用来并行运行异步函数的。

我将通过.then 链接函数调用并收集响应:

function doOperation() {
  return doSomeAsyncOperation().then(function (resp1) {
    return doAnotherAsyncOperation().then(function(resp2) {
      return [resp1, resp2];
    });
  });
}

DEMO

我想说这里更清楚doAnotherAsyncOperationdoSomeAsyncOperation 之后执行,并且两个调用的结果都可供doOperation 的调用者使用。

您可能必须为失败案例做类似的事情。

【讨论】:

  • 它有效。谢谢你。我第一次了解 .then filters。我第一次明白,当 jQuery 文档将 $.when 签名声明为“$.when(deferreds)”时,它们实际上意味着 deferredspromises
  • 不客气!延迟对象(在 jQuery 中)是 Promise 的超集。单独的 Promise 只允许您向它添加回调,但它不允许您更改其状态(解决/拒绝)。延迟对象让您更改其相应承诺的状态。之所以存在这种区别,是因为the concept of the promise 是重要的,而不是它的状态如何改变。有多种方法可以进行状态更改,jQuery 开发人员决定将他们的解决方案命名为“延迟对象”。
  • 好的! .... 同样在您的第一个建议中,您为“then”提供了“doneFilter”,但是,当 doneFilter 返回的承诺失败时,then 承诺也失败。我想你应该为 failFilter 返回相同的承诺!?
  • .then 返回的承诺与“完成”或“失败”过滤器返回的承诺具有相同的状态。所以在你的情况下,如果doAnotherAsyncOperation 返回的承诺被拒绝,def2 也将被拒绝。示例:jsfiddle.net/adZ4W/2。这就是你想要的,对吧?
  • 没错。然后可能会在 doneFilter 和 failFilter 中返回不同的 deferred,以及原始 deferred 解决还是拒绝,这将选择分别考虑来自 doneFilter 或 failFilter 的承诺,而后一个承诺将在转,决定最终调用哪些附加回调,完成或失败回调。对吗?
【解决方案2】:

我对 Deferred 没有任何经验(我也不完全理解它的作用),但如果您只是想进行链式操作,这样的方法可以吗?

function doOperation(operations) {
    var wrapper = {};
    wrapper.index = 0;
    wrapper.operations = operations;
    wrapper.onthen = $.proxy(function() {
        if (this.index < this.operations.length) {
            this.operations[this.index]().then(this.onthen);
        }
        this.index++;
    }, wrapper);
    wrapper.onthen();
}

这是一个演示:http://jsfiddle.net/vz6D7/2/

【讨论】:

    猜你喜欢
    • 2016-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多