【问题标题】:Missing progress notifications when chaining jQuery promises链接 jQuery 承诺时缺少进度通知
【发布时间】:2012-09-13 08:32:50
【问题描述】:

如果我创建一个 Deferred 对象,它会像我预期的那样报告进度。

var d1 = function() {
    var d = $.Deferred();
    d.notify('d1');
    d.resolve('d1');
    return d.promise();
};

d1().progress(function(a) {
    log('Progress: ' + a);
});

​ 但是,如果我使用 then() 链接两个 Deferred 对象,则不会调用进度回调。

d1().then(d1).progress(function(a) {
    log('Progress: ' + a);
});

在我看来 then() 应该传播进度通知,但事实并非如此。我错过了什么吗?

我已经用 jQuery 1.8.0 和 1.8.1 对此进行了测试。一个完整的工作示例在这里:http://jsfiddle.net/eWQuG/13/

【问题讨论】:

    标签: javascript jquery jquery-deferred deferred


    【解决方案1】:

    我可以看到发生了什么,但解释起来有点棘手。您可能需要多读几遍...

    在测试 1 中,传递给 test() 的承诺是“原始承诺”,即。 d1() 返回的对象。很简单。

    在测试 2 中,传递给test() 的对象是由d1().then(d2).then(d3) 产生的 承诺。不那么简单。这个新的 Promise 将只继承原始 Promise 的一些属性 - 不包括它的 progressCallbacks(在原始 Promise 中使用 notify() 放置)。这对于.then() 返回的承诺是合理的,因为.then() 旨在放置其自己的 doneCallbacks、failCallbacks 和 progressCallbacks,而不是将延迟/承诺的那些传播到其紧邻的左侧.简而言之,.then() 就像它的名字所暗示的那样 - 它指定了在处理其前面的延迟/承诺之后要做什么。

    通过保留对原始承诺的引用(即d1() 的输出),您可以更好地了解发生了什么,从而允许在测试 2 之前和之后运行简单的测试 1。

    这是一个综合测试 3:

    log('-- Test 3 --');
    var p = d1();//p is a promise
    test(p);//equivalent to Test 1
    test(p.then(d2).then(d3));//equivalent to Test 2
    test(p);//equivalent to Test 1 again
    

    DEMO

    在日志中,您将看到test(p) 的行为在两种情况下都是相同的。但是,test(p.then(d2).then(d3)) 的行为有所不同,因为传递的对象不再是原来的 Promise,而是一个没有 progressCallbacks 的新 Promise。

    编辑

    Ryan,在实现你想要的东西时可能值得考虑:

    d1().then(d2).progress(function(a) {
        log('Progress: ' + a);
    });
    

    是一个链条可以重新排列如下:

    d1().progress(function(a) {
        log('Progress: ' + a);
    }).then(d2);
    

    进度回调因此应用于原始承诺,并且因为.progress() 沿链传播原始承诺,.then() 仍将像以前一样运行。

    两个版本都有效,但适用于不同的情况。

    如果我是对的,那么也许这是对您问题的简短回答。

    【讨论】:

    • 谢谢,我同意你的分析。我想我会推出自己的传播通知的链接机制。可惜没有内置方法。
    • Ryan,为了响应您对自定义方法的感知需求,我在上面添加了一些想法。
    【解决方案2】:

    您在测试中做了一些不合逻辑的奇怪事情。

    第一,你在返回之前解决了承诺,这违背了承诺的目的。 Promise 回调不应该在先前解决的 Promise 上被调用,就这么简单。

    var p = $.Deferred();
    p.then(function(p){log("ok")}).progress(function(p){log("progress " + p)});
    p.notify('n1'); // will call handler and be logged
    p.resolve();
    p.notify('n2'); // will not call handler and will not be logged
    

    第二,您在设置进度回调之前调用了“通知”,但这在某种程度上仍然可以正常工作 - 似乎 jQuery 的特定通知实现有点异步......除了链接失败。如何或为什么,我不知道,但我认为调试并不重要,因为无论如何您的使用不正确。

    查看您的小提琴的此更新: http://jsfiddle.net/eWQuG/15/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多