【问题标题】:Async handling gives unexpected results when using nested jQuery $.when使用嵌套 jQuery $.when 时,异步处理会产生意想不到的结果
【发布时间】:2012-05-26 22:13:57
【问题描述】:

我有许多 ajax 调用,每个调用都会触发其他 ajax 调用。然后我想等待后者以处理来自它们的数据。这是(伪)代码:https://gist.github.com/2795435 问题是第二个$.when-always 表达式的回调函数在promises2 数组的所有延迟都被解决/拒绝之前被触发。怎么会这样?如我所见,第一个 $.when-always 回调将不会被调用,直到 promises1 数组的所有延迟都被解决/拒绝并且到那时所有对 promises2 的 ajax 调用都已经完成,因此应该回调第二个$.when-alwayspromises2 中的所有延迟都被解决/拒绝之前不会被调用。

【问题讨论】:

  • 文字墙对你造成超过 9000 点伤害。你死了。
  • 看你的代码,你有更“真实”的代码吗?
  • 一些代码痕迹将是锦上添花:)

标签: jquery asynchronous jquery-deferred


【解决方案1】:

看起来,在await() 中,jQuery 在触发与last getJson 关联的回调之前触发promises1 的always 回调以进行响应。因此,在await() 中,当内部.when() 触发其always 回调时,promises2 数组缺少一个promise。

如果我是对的,那么您应该能够运行测试来证明这一点(每个 json 响应有一个 .get()),在每种情况下,除了一个内部 .gets 之外,其他所有情况(永远不会更多也永远不会) less) 将在调用doSomethingToTheDataStoredInSomeGlobalVariableBelow() 时完成。

无论我是否正确,一种解决方法(不是我确定的唯一一种)将是以下几行:

function A() {
    var promisesA = [];
    for (var i = start; i < end; i++) {
        promisesA.push( B(someUri) );
    }
    $.when.apply($, promisesA).always(function() {
        doSomethingToTheDataStoredInSomeGlobalVariableBelow();
    });
}

function B(uri) {
    var d = new $.Deferred(),
        promisesB = [];
    $.getJSON(uri, function(data) {
        someCollectionFrom_data.each(function () {
            promisesB.push($.get(someUriFrom_this, function(data) {
                extractSomeStuffFrom_data_AndStoreInSomeGlobalVariable();
            }));
        });
        $.when.apply($, promisesB).done(function() {
            d.resolve();
        }).fail(function() {
            d.reject();
        });

    }).error(function(){
        d.reject();
    });
    return d;
}

Here's a demo - 修改后的代码使其像小提琴一样工作。

在这里(排除错误),数组promisesA 像以前一样在每个uri 中填充一个$.Deferred,但是这一次当它们对应的getJSONs 解决/失败时,不允许这些延迟自动解决。相反,当所有关联的.get()s 已通过函数B() 的数组promisesB 管理时,每个Deferred 都会“手动”解决(其中将有几个实例,每个实例都在@ 形成的闭包中捕获987654339@)。

此架构可以被视为 ajax 调用(.json()s.get()s)的“向下”级联,以及 .always()s 的相互“向上”级联。 (混合.done()/.fail()/.always()同样适用。)

【讨论】:

  • 感谢您的回复!我按照您的建议对每个 json 响应使用一个 .get() 进行了测试,但所有的 get 实际上都完成了。关于您建议的解决方法,B() 中的always-callback 不会立即被调用,因为此时promisesB 集合很可能是空的(它是异步填充的,因此when-表达式将在之前执行getJSON 调用调用了它的回调)?
  • 当,你是对的。我会看看我能不能想出更好的东西。
  • 再看一下,我将$.when... 结构向上移动到了getJSON 回调中。
  • .... 并添加到 B() 中,(a) .error() 处理程序,如果 getJSON() 本身失败,则会导致 d 被拒绝,以及 (b) @ 987654356@ 处理程序,如果 promisesB 中的任何承诺失败,这将再次导致 d 被拒绝。因此,d 不会在错误条件下挂起,并且(我希望)一些内存可以通过垃圾收集来恢复。
  • 它有效,太棒了!有趣的是,直到我将promises-collections 更改为非全局的,它才起作用,不知道为什么不这样做。仍然不明白为什么我最初的方法不起作用?无论如何,非常感谢!
猜你喜欢
  • 2021-03-10
  • 2020-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-12
  • 2017-03-19
  • 2021-10-04
  • 1970-01-01
相关资源
最近更新 更多