3

如果我创建一个 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/

4

2 回答 2

2

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

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

在测试 2 中,传递给的对象test()是由. 不那么简单。这个新的 Promise 将只继承原始 Promise 的一些属性 - 不包括它的 progressCallbacks(如在原始 Promise 中放置的那样)。这对于. _ 简而言之,正如它的名字所暗示的那样——它指定了在处理了之前的延迟/承诺之后要做什么。d1().then(d2).then(d3)notify().then().then().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

演示

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

编辑

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

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

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

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

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

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

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

于 2012-09-21T01:46:36.870 回答
1

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

一,你甚至在返回之前就解决了承诺,这违背了承诺的目的。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/

于 2013-06-04T09:59:18.793 回答