【问题标题】:attempting to break jQuery promise chain with .then, .fail and .reject试图用 .then、.fail 和 .reject 打破 jQuery 承诺链
【发布时间】:2012-08-22 09:56:12
【问题描述】:

更新:这个问题是 jQuery 1.7 vs 1.8 的结果。永远不要在 1.7 中使用 Promise,因为它们不能通过在 .then 中返回 Promise 进行链接。 1.8 看起来他们没有搞砸。

http://jsfiddle.net/delvarworld/28TDM/

// make a promise
var deferred = $.Deferred();
promise = deferred.promise();

// return a promise, that after 1 second, is rejected
promise.then(function(){
    var t = $.Deferred();
    setTimeout(function() {
        console.log('rejecting...');
        t.reject();
    }, 1000);

    return t.promise();
});

// if that promise is successful, do this
promise.then(function() {
    console.log('i should never be called');
})

// if it errors, do this
promise.fail(function() {
    console.log('i should be called');
});

deferred.resolve();

预期:'我应该被调用'

实际:'我永远不应该被调用'

问题:我想要链接回调并让其中任何一个能够打破链接并触发fail 函数,并跳过其他链接的回调。我不明白为什么所有的thens都被触发而fail没有被触发。

我来自 NodeJS 的 Q 库,所以我先用.then 进行了尝试。但是,将其更改为.pipe 没有任何效果。

【问题讨论】:

  • .then() 返回 t 没有任何作用。拒绝t 也不会以任何方式影响原始延迟对象。来自.then 的回调直到它们应用到的延迟对象被解析或拒绝后才会被调用。一旦被解决或拒绝,就不能再次被拒绝或解决。
  • 为了更容易理解,请将 .then 替换为 .done,因为在您的情况下,它们的作用完全相同。
  • 我相信至少在 Q 中,在then 中返回一个承诺会将其添加到链中。否则链接的正确方法是什么?
  • 相关:Problems inherent to jQuery $.Deferred,尤其是当你带着 Q 的期望而来时。

标签: jquery deferred chain promise


【解决方案1】:

你没有重新定义promise的值,试试这个:

http://jsfiddle.net/28TDM/1/

var deferred = $.Deferred();
promise = deferred.promise();

promise = promise.then(function(){
    var t = $.Deferred();
    setTimeout(function() {
        console.log('rejecting...');
        t.reject();
    }, 1000);

    return t.promise();
});

promise.then(function() {
    console.log('i should never be called');
})

promise.fail(function() {
    console.log('i should be called');
});

deferred.resolve();

显然它确实按照您想象的方式工作,只是没有记录https://api.jquery.com/deferred.then。很酷。这是 jQuery 1.8.0 中添加的新功能,他们很可能只是没有更新文档。

【讨论】:

  • 我仍然有这个流程的问题,但无法为它制作一个通用的 jsfiddle。我想知道这个小提琴是否只是巧合。
  • @AndyRay 如果有帮助的话,这就是让我的小提琴奏效的改变:bugs.jquery.com/ticket/11010
  • 另外,如果您使用.pipe 代替.then,它也可以工作。 jsfiddle.net/28TDM/2 然后,如果你链接它而不是回到promise 变量,你不必重新定义promisejsfiddle.net/28TDM/3
  • 更新:我发现了实际问题。我们使用的是 jQuery 1.7。 1.7 中的 Promise 很糟糕而且很糟糕。它们在 1.8 中已修复,看起来管道已被弃用,感谢上帝。
  • 哈哈,抱歉,我的大脑将其解读为“我永远不应该被召唤”。再次抱歉。干得好!
【解决方案2】:

恕我直言,你没有链接任何东西。 您的第二个.then 与第一个.then 所附加的承诺相同

为什么?

请注意,then 将始终返回新的承诺,而不是更改它所附加的承诺。没有副作用。

例如:

var promiseX = promiseA
                 .then(function() { return promiseB; })
promiseX.then(function() { return promiseC; });

promiseA 不会改变它的值 附上then;它会保持原样。

promiseX将是第一个then的返回值,即promiseB

所以第二个then实际上附加到promiseB

这正是@Kevin B 在他的回答中所做的。


另一个解决方案是,由于.then 将返回新的承诺,您可以像下面这样链接.then 函数。

var promiseX = promiseA
                 .then(function() { return promiseB; })
                 .then(function() { return promiseC; });

这一次,第一个then 附加到promiseA,猜猜第二个then 附加到哪个promise?

你是对的。这是promiseB,而不是promiseA。因为第二个then实际上是附加到第一个then的返回值上的,即promiseB

最后将第二个then的返回值赋值给promiseX,所以promiseX等于promiseC

好的,回到 OP 的问题。以下代码是我的答案。

var deferred = $.Deferred();
promise = deferred.promise(); // this is the first promise

promise.then(function(){ // callbacks for 1st promise
    var t = $.Deferred();
    setTimeout(function() {
        console.log('rejecting...');
        t.reject();
    }, 1000);
    return t.promise(); // this is the 2nd promise
    // return $.Deferred().reject(); // To reject immediately.
}).then(function() { // callbacks for 2nd promise
    console.log('i should never be called');
}, function() {
    console.log('i should be called');
})

deferred.resolve();

【讨论】:

  • 否决票可能是因为.then 返回了一个新的承诺。你错了。
  • 当然.then返回一个新的承诺,我知道。但是看看 OP 的例子,i should never be called 附加到对应于deferred 而不是t 的promise。但是 OP 预计他/她拒绝了承诺 t 并且第二个 then 附加到 t.promise (但事实并非如此)。我正是这个意思。看看我的代码,第二个then 附加到t.promise,这正是 OP 所期望的。不是吗?
  • 哦。答案中第二句话的措辞似乎暗示了其他意思。第二个.then 没有附加到与第一个then 相同的promise 上。即使第一个“then 回调”没有返回承诺,第二个 then 仍将附加到不同的 Deferred 实例,因为 .then 总是返回一个新的延迟。 Example on jsfiddle.
  • 哦!我认为投反对票的人像我一样误解了这句话。您的意思是 OP 的 秒然后附加到相同的承诺。很容易将您的语句错误地解释为 .then 像选择器一样链接,但原来的承诺链接在那里。 +1。
  • @doug65536。您在最后一条评论之前的评论是错误的。是的,.then 总是返回一个新的承诺,但是 OP 没有将返回的承诺分配给任何变量,所以变量 promise 仍将等于 deferred.promise(),因此第二个 then 附加到 deferred.promise() .这就是为什么@Kevin B 将第一个then 返回的承诺分配给promise,这会将变量promise 更新为t.promise()。在我的回答中,第一个 then 返回一个新的承诺 (t.promise),第二个 then 附加到该承诺上。感谢您的支持;)
猜你喜欢
  • 2020-02-23
  • 2018-03-18
  • 2023-04-03
  • 2017-11-23
  • 1970-01-01
  • 1970-01-01
  • 2021-10-17
  • 1970-01-01
相关资源
最近更新 更多