问题 试图用.then,.fail和.reject打破jQuery承诺链


更新:此问题是jQuery 1.7 vs 1.8的结果。不要在1.7中使用承诺,因为它们不能在一个承诺中回复 .then。 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 函数,并跳过其他链式回调。我不明白为什么所有的游戏都被触发,并且没有触发失败。

我来自NodeJS的Q库,所以我尝试了 .then 第一。但是,将其更改为 .pipe 没有效果。


3977
2017-08-27 21:41


起源

返回 t 从 .then() 没有做任何事。拒绝 t 也不会以任何方式影响原始的延迟对象。来自的回调 .then 直到他们应用的延迟对象被解析或被拒绝后才被调用。一旦解决或拒绝,他们就不能被拒绝或再次解决。 - Kevin B
为了使这更容易理解,请更换 .then 同 .done 因为在你的情况下,他们完全一样。 - Kevin B
至少在Q中,我相信,在里面回应一个承诺 then 将它添加到链中。除此之外,链接的正确方法是什么? - Andy Ray
有关: jQuery $ .Deferred固有的问题,特别是当你从Q得到你的期望。 - Bergi


答案:


你没有重新定义它的价值 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中添加的新功能,很可能他们没有完成更新文档。


10
2017-08-27 22:03



我仍然遇到这个流程的问题,但是无法为它制作一个通用的jsfiddle。我想知道这个小提琴是否只是巧合。 - Andy Ray
@AndyRay如果有任何帮助,这就是让我的小提琴起作用的变化: bugs.jquery.com/ticket/11010 - Kevin B
另外,如果你使用 .pipe 代替 .then 它也会奏效。 jsfiddle.net/28TDM/2 然后,如果你链接它而不是回到 promise 变量,您不必重新定义 promise。 jsfiddle.net/28TDM/3 - Kevin B
更新:我找到了实际问题。我们使用的是jQuery 1.7。 1.7中的承诺破碎而且糟糕。它们固定在1.8,看起来管道已被弃用,感谢上帝。 - Andy Ray
haa opss抱歉,我的大脑读到它为“我永远不应该被称为”。再次抱歉。优秀作品! - vsync


恕我直言,你没有任何链接。 你的第二个 .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; });

这一次,第1次 then 附在 promiseA,并猜测哪个承诺是第二个 then 被附着?

你是对的。它的 promiseB不是 promiseA。因为第二个 then 实际上是附加到第1个的返回值 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();

0
2017-09-07 07:28



为什么没有评论就downvote? - lzl124631x
downvote可能是因为 .then 返回一个新的承诺。你错了。 - doug65536
当然 .then 我知道,回复新的承诺。但是看看OP的例子, i should never be called 附加于对应的承诺 deferred 不 t。但OP期望他/她拒绝承诺 t 和第二个 then 附在 t.promise (但事实并非如此)。我正是这个意思。看看我的代码,第二个 then 附在 t.promise,这正是OP的预期。不是吗? - lzl124631x
哦。答案中你的第二句话的措辞似乎暗示不然。第二 .then 与第一个没有相同的承诺 then。即使第一个“然后回调”没有返回承诺,第二个仍然会附加到另一个 Deferred 例如,因为 .then 总是返回一个新的延迟。 关于jsfiddle的例子。 - doug65536
哦!我认为downvote来自于一个误解了这句话的人,就像我一样。你的意思是 OP的 第二个是同一个承诺。很容易误解你的陈述 .then 像选择器一样的链,虽然原始的承诺链。 +1。 - doug65536