【问题标题】:Chaining jQuery deferred by updating deferred inside then()?通过在 then() 中更新 deferred 来链接 jQuery deferred?
【发布时间】:2017-03-07 09:50:32
【问题描述】:

我正在学习使用 jQuery Deferred,并且正在考虑链接多个 deferred。这是我的问题的简化版本:

var def1 = $.ajax(...); // ajax call 1
var def2 = null, def3 = null;

$.when(def1)
  .then(function() {
    def2 = $.ajax(...); // ajax call 2
    return def2;
  }).then(function() {
    def3 = $.ajax(...); // ajax call 3
    return def3;
  });

然后在上面的代码下面的某个地方,我有:

$.when(def1, def2, def3)
  .then(function() {
    // run some code... .e.g. run foo();
  });

上面的代码是错误的。它不能做我想要的。我的实际意图基本上是:

我想先运行 ajax call 1。

如果 ajax 调用 1 成功,则运行 ajax 调用 2。(添加的好处是:如果 ajax 调用 1 不成功和/或其返回的结果未通过我的手动验证,请提醒用户并运行一些代码,例如 bar()。)

如果 ajax 调用 2 成功,则运行 ajax 调用 3。(同样适用)

然后我想仅在 def3 已解决时才运行一些代码(例如 foo() )。在运行 foo() 之前,我实际上并不关心 def1 和 def2 是否已解决。 (如果def3被拒绝,我也想运行另一段代码,如果可能的话。)

一开始我无法初始化def2(ajax call 2)和def3(ajax call 3)的原因是我想根据ajax call 1返回的结果来修改ajax call 2的选项。 ajax 调用 3 的方式相同,具体取决于 ajax 调用 2 的结果。

以我对deferred的知识和理解有限,上面的代码基本上不能产生我想要的。

因为 def1 在 def2 被初始化和触发之前就被解析了,所以底部的代码会在 def2 被启动之前过早地运行 foo()...

所以,我正在寻求帮助和建议。看看是否有人知道如何重写上面的代码并让它按照我上面写的意图运行。我很抱歉我的无能。

提前谢谢大家。

【问题讨论】:

  • jQuery 的哪个版本?这方面的重大变化发生在 v3.x。
  • 抱歉回复晚了。我正在使用 jQuery 版本 1.11
  • 我不明白这些句子:"然后我想运行一些代码(例如 foo() ),只有当 def3 已经解决了。在运行 foo() 之前,我不'实际上并不关心 def1 和 def2 是否已解决。(如果 def3 被拒绝,如果可能的话,我也想运行另一段代码。)" 如果我明白你当时所说的话, def3 只有在def1def2 都成功时才会运行。那你怎么不在乎他们是否已经解决了?
  • 嗯,没错。简单来说,我想在 def3 解决后运行foo()。只是我主要关心的是在运行 foo() 之前解决 def3,并且从逻辑上讲,为了启动 def3,应该首先解决 def1 和 def2。
  • 您拥有的代码可能有点过于复杂,但我认为它确实符合您的描述。哪种情况不能按预期处理?

标签: javascript jquery ajax deferred chaining


【解决方案1】:

你不需要使用when,当你想并行运行多个延迟时,它真的更好用。试试这个:

var d1 = $.ajax(...);
var d2 = d1.then(function () {
  if (invalid) {
    return $.Deferred().reject("Invalid");
  }
  return $.ajax(...);
});
var d3 = d2.then(function () {
  if (invalid) {
    return $.Deferred().reject("Invalid");
  }
  return $.ajax(...);
});

d3.done(function () {
  // This is called when we're all done.
});

这可以简化为:

$.ajax(...).then(function () {
  if (invalid) {
    return $.Deferred().reject("Invalid");
  }
  return $.ajax(...);
}).then(function () {
  if (invalid) {
    return $.Deferred().reject("Invalid");
  }
  return $.ajax(...);
}).done(function () {
  // This is called when we're all done.
})
// Use this to handle failure. You can also add to individual
// deferred objects to handle each failure differently.
.fail(function () {
  // Do something.
});

要处理失败,您可能需要在 then 中添加另一个回调:

.then(function () {
  if (invalid) {
    return $.Deferred().reject("Invalid");
  }
  // Do stuff
}, function (err) {

})

【讨论】:

  • 如果我这样做,如何在then()中添加手动验证代码并确定返回的数据有效,如果数据有效,则链接另一个then();如果数据无效,则输出错误(和/或返回空promise?)
  • 您需要拒绝延迟以将其短路。答案中的示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-31
  • 1970-01-01
相关资源
最近更新 更多