【问题标题】:multiple simultaneous ajax requests broker多个同时 ajax 请求代理
【发布时间】:2014-10-11 16:11:30
【问题描述】:

如何协调同时进行的ajax调用,只在所有调用都完成后才采取行动?

是否有一个方便的 javascript 帮助程序库可以协调多个同时对数据库的 ajax 调用,并在所有 ajax 数据获取都返回其数据时调用指定的回调?我想向这个“协调器”或“代理”提交一份准备就绪的 ajax 调用字典,以及我的 WhenAllCompleted 回调函数。

用例很常见:在将数据库记录绑定到 UI 之前,必须填充所有外键数据关系的下拉列表,以便用户看到有意义的值而不是整数键通常存储在记录中。

如果已经有一个强大的标准库可以做到这一点,我宁愿不重新发明所有的管道代码来跟踪每个 ajax 请求的状态。

编辑: 这是描述我想要做什么的伪代码:

           when ajax1fetch is finished
           and
           ajax2fetch is finished
           and 
           ajax3fetch is finished
           and SELECT1 is populated
           and SELECT2 is populated
           and SELECT3 is populated
           bindRecordToUI()

在我重构代码以使用 $.when() 之前,我在 .ajax() 成功回调中获取数据,并在该回调中填充 SELECT;填充 SELECT 后,我将记录绑定到 UI。

如果我们为 $.when 提供 ajax 调用列表,则在 ajax 请求完成时调用 done 回调,这发生在填充 SELECT 之前(如果 SELECT 的项目列表很长)。

不知何故,我需要将 SELECT 元素的填充作为附加的 when 条件,并找到一种方法将 ajax 调用返回的数据路由到填充函数,如果不执行 SELECT-populate 函数在 .ajax 成功回调中。

【问题讨论】:

  • 听起来你想要jQuery.when(),因为你已经在使用jQuery了。

标签: javascript jquery ajax


【解决方案1】:

你在 JS 中寻找promises。这是一个不错的框架QallSettled() 函数就是你要找的。​​p>

Q.allSettled([saveToDisk(), saveToCloud()]).spread(function (disk, cloud) {
    console.log("saved to disk:", disk.state === "fulfilled");
    console.log("saved to cloud:", cloud.state === "fulfilled");
}).done();

代码取自API-reference

【讨论】:

  • 当一个已经在使用的库(jQuery)具有开箱即用的支持时,为什么还要包含另一个库?
  • @ajp15243:因为 Q 更好 :-) 当然,这取决于需要多少功能
  • @Bergi 我当然不会盲目地支持 jQuery。然而,Q 也会分离出 futures/deferred/promise 功能,因此如果代码曾经从 jQuery 迁移到其他东西,则不需要触及该部分。老实说,我现在比我更喜欢这个答案:P。
  • 哪个会更好地处理我遇到的问题,其中 ajax 调用已完成,但使用数据填充 UI SELECT 尚未完成。在所有 SELECT 都被填充之前,我不想将我的记录绑定到 UI,这发生在获取数据之后的某个时间。
  • @Tim 听起来你的问题对于异步任务来说更基本一些,而不是依赖于库,但是 q 可能有一些技巧。
【解决方案2】:

由于您已经在使用 jQuery,您可以使用 jQuery.when() 方法等待多个 Deferreds 完成。请注意,jQuery.ajax()(及其包装方法,如jQuery.get())返回一个jqXHR 对象,它是Deferred 的一种类型。

您将从$.ajax 或等效调用中获得Deferreds,然后将这些全部传递给$.when。你会得到一个Promise,它基本上是一个只读的Deferred*。然后,您可以将完成/错误处理程序附加到此 Promise,一旦您传入的所有 Deferreds 被解决,或者如果您的任何一个 Deferreds 被拒绝,它就会被拒绝。

var def1 = $.ajax(),
    def2 = $.ajax({ /* some params */});

var masterPromise = $.when(def1, def2);

masterPromise.done(function() {
    console.log('def1 and def2 are done!');
});

  • Deferred 允许附加各种完成和错误处理程序,以及解决和取消以及以其他方式控制异步操作​​。 Promise 只允许附加处理程序,并且不允许控制异步操作​​。您可以使用 Deferred.promise() 方法从 jQuery Deferred 获取 Promise

【讨论】:

  • 感谢您提供非常好的答案。我已经接受了托马斯的第一名,但我要投票给你。
  • @Tim 谢谢。您可以随时更改接受的答案:)。但我会留给你,因为你知道哪个答案最适合你的情况。
  • 遇到了问题 :-) 当其中一个 ajax 调用返回许多行,并且在将数据行添加到下拉列表之前调用了 `masterPromise' 的 done 方法时该怎么办?
  • @Tim 我认为从技术上讲这是另一个问题......但我刚刚想到的一个想法是做一些延迟链接。 d1 是获取行的 AJAX 调用。不要将其传递给$.when。自己创建另一个延迟:var d2 = $.Deferred();。将d2 传递给$.when。当 d1 完成时,让 done 处理程序填充行,然后解析 d2 (d2.resolve())。这样,行将在d2 解决之前填充,并且$.when 承诺直到d2 才解决,因此您对行填充有一个传递等待。有道理?这对我来说听起来有点 hacky,但应该可以。
  • 好的。我会提出另一个问题。
猜你喜欢
  • 2011-11-28
  • 2017-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多