【问题标题】:Waiting for multiple deferred objects to be finished and use the resolved values等待多个延迟对象完成并使用解析的值
【发布时间】:2016-01-21 08:29:31
【问题描述】:

我正在尝试找出一种方法来等待多个延迟对象并在完成后处理它们,可能就像为延迟对象开始下一组。

我被卡住了,因为以下结果不是预期的。 我期待结果为

allDone resovled values are 1,2,3

实际结果是

allDone resovled values are 1,2
var dfd1 = new $.Deferred();
var dfd2 = new $.Deferred();
var dfd3 = new $.Deferred(); 
var dfds = [ dfd1, dfd2, dfd3 ]; 
var resolvedValues = [];

$.when.apply($, dfds).done(function() {     
    dfds.forEach(function(dfd){
        console.log("inloop");      
        dfd.promise().done(function(value) {
            resolvedValues.push(value);         
        });     
    });
    console.log("allDone resovled values are" + resolvedValues);
})

dfd1.resolve(1);
dfd2.resolve(2);
dfd3.resolve(3);

【问题讨论】:

  • 请花点时间正确格式化您的代码,之前它是不可读的。拥有清晰易读的示例意味着您更有可能获得快速准确的答案。
  • 没问题。我已经为你编辑了布局。
  • @T.J.Crowder 确实,奇怪的结果:jsfiddle.net/d4nxmdLx/1 ?!事实上并不奇怪,因为我们最后解析了 dfd3,所以我的例子不相关
  • @A.Wolff:我知道为什么了。又是 jQuery 损坏的同步/异步的东西。
  • @user3397062:一旦有答案,就不能明显改变问题;我已经回滚了那个编辑。如果在尝试将此答案应用于您的 ajax 情况后仍然遇到问题,请发布一个新问题,询问您在应用此问题时遇到的具体问题。

标签: jquery


【解决方案1】:

为什么,见下文。但是你把它复杂化了。 :-) 你给你从when 得到的最终承诺的回调给你解析的值作为参数:

$.when.apply($, dfds).done(function(a, b, c) {
    // Here, a is 1, b is 2, c is 3
    // Or you can access them on `arguments`
})

实例:

var dfd1 = new $.Deferred();
var dfd2 = new $.Deferred();
var dfd3 = new $.Deferred(); 
var dfds = [ dfd1, dfd2, dfd3 ]; 
var resolvedValues = [];

$.when.apply($, dfds).done(function() {
    // Use a trick to turn `arguments` into a real array
    var a = Array.prototype.slice.call(arguments);
    // Show what we got
    console.log("allDone: " + a.join(", "));
})

dfd1.resolve(1);
dfd2.resolve(2);
dfd3.resolve(3);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

旁注:我假设您是故意处理一个数组。如果你有固定数量的 Promise 需要等待,只需使用更简单的形式

$.when(dfd1, dfd2, dfd3).then(function(a, b, c) {
    // ...
});

为什么你会得到非常奇怪的结果:jQuery 的 Deferred/Promise 对象存在问题,因为它们是混乱:当您对它们调用done 时,您不知道您的回调是同步 还是异步 执行。这是一个严重的缺陷,并且是真正的 Promises/A+ 实现所没有的(回调始终是异步的)。

如果承诺还没有解决,jQuery 将异步调用回调。但如果它没有解决,它会调用它同步

var d1 = $.Deferred();
d1.done(function() {
    console.log("I'm called asynchronously");
});
d1.resolve();

var d2 = $.Deferred();
d2.resolve();
d2.done(function() {
    console.log("I'm called synchronously");
});

所以在您的代码中发生的情况是,when 触发的整个 done 回调在期间在最后一个已解决的承诺 (dfd3) 的 done 回调中被触发。由于直到 done 回调完成后,promise 才被标记为已解决,所以当您的代码运行时,dfd1dfd2 已解决,但 dfd3 仍在处理中正在解决。因此,dfd1dfd2 会同步调用您的内部回调,而dfd3异步调用。因此,您在将 dfd3 返回值推送到您的数组之前输出结果。

【讨论】:

  • 不应该在 jq 3.x 中修复吗?因为只是在 jsFiddle 中使用 jQuery edge 检查,尽管jQuery.Deferred objects have been updated for compatibility with Promises/A+ and ES2015 Promises 仍然会出现这种行为
  • 超级明白你的解释。
  • @A.Wolff:如果您使用then 而不是done,您还会看到这种行为吗?请注意,发行说明谈到了then(Promises/A+ 函数)。他们可能已经离开了done 向后兼容的旧方式。
  • @T.J.Crowder 你好,我的错,then() 按预期工作!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多