我有一个可以解决或拒绝的承诺。我想在这些情况下做一些具体的事情,然后继续解决承诺链(基本上我想“抓住”被拒绝的承诺,做一些事情,然后继续解决)。
这是一个功能代码段,显示了我遇到的问题:
var def = $.Deferred();
def.then(
function() {
console.log('first success handler');
},
function() {
console.log('first fail handler');
return $.Deferred().resolve();
}
);
def.then(
function() {
console.log('second success handler');
},
function() {
console.log('second fail handler');
}
);
def.done(function() {
console.log('done handler');
});
def.reject();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
预期结果:
first fail handler
second success handler
done handler
目前的结果:
first fail handler
second fail handler
根据jQuery文档:
从jQuery 1.8开始,deferred.then()方法返回一个新的promise 可以过滤通过a延迟的状态和值 功能[...]。这些过滤器函数可以返回一个新值 传递给promise的.done()或.fail()回调,或者它们 可以返回另一个可观察对象(Deferred,Promise等) 将其解决/拒绝的状态和值传递给promise 回调。
所以我不知道为什么这不起作用。我期望在第一个失败处理程序中返回已解析的promise以允许其余的promise链继续解析。
答案 0 :(得分:4)
模式......
var def = $.Deferred();
def.then(successHandler, errorHandler);
def.then(successHandler, errorHandler);
// etc.
...形成两个(或更多)分支,每个then()
仅依赖于def
。每个分支都具有独立的过滤能力,但没有被利用。
这与......非常不同。
var def = $.Deferred();
def.then(successHandler, errorHandler).then(successHandler, errorHandler); // etc.
...形成单链(没有分支)。第一个then()
取决于def
,第二个then()
取决于第一个then()
。在这里,第一个then()
的过滤能力通过链接另一个then()
(等等)来利用。
因此,您可以通过将问题中的代码转换为第二种模式来获得预期的输出:
var def = $.Deferred();
def.then(function() {
console.log('first success handler');
}, function() {
console.log('first fail handler'); // (1)
return $.Deferred().resolve();
}).then(function() {
console.log('second success handler'); // (2)
}, function() {
console.log('second fail handler');
}).done(function() {
console.log('done handler'); // (3)
});
def.reject();
简而言之,这就是承诺链接的全部意义。
但不要忘记完全分支。在某些情况下,这是至关重要的。例如,在this answer中,batchRequests()
返回_p
,它可以被调用者(即一个分支)进一步链接,但也会与_p.then(..., ...)
形成自己的私有分支。不要担心,如果你不能完全遵循它 - 它相当复杂 - 现在相信我,分支是解决方案的重要组成部分。
答案 1 :(得分:1)
文档的重要部分是
deferred.then()
方法返回一个新的承诺
然而,您丢弃了该返回值,并调用了原始.then(…)
上的下一个def
。
您需要使用
var p = $.Deferred().reject().promise();
p.then(function() {
console.log('first success handler');
}, function() {
console.log('first fail handler');
return $.Deferred().resolve();
}).then(function() {
//^^^^^ chain directly on the result
console.log('second success handler');
}, function() {
console.log('second fail handler');
}).then(function() {
//^^^^^
console.log('done handler');
});
答案 2 :(得分:0)
您的代码实际上正在排队的是两个处理程序(通过then
函数)。当延期被拒绝时,它不能再被改变。
当Deferred被拒绝时,第一个then
处理程序将触发编写第一个控制台消息。
行return $.Deferred().resolve();
将创建一个新的已解决的Deferred,但它不会&#34;返回&#34; ed到第二个then
,因为该处理程序已经绑定到第一个Deferred实例。< / p>
因此,您的第二个then
处理程序现在也将触发failFilter(Deferred被拒绝时的处理程序)。
您可以采取的一种方法是在拒绝(或解决)延期时传递值。然后,您可以收到该响应并采取补救措施,如此(有点人为的)样本所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<div id="test"></div>
<script>
var def = $.Deferred();
def.then(
function () {
console.log('first success handler');
},
function (response) {
console.log('first fail handler');
console.log(response);
}
);
def.then(
function () {
console.log('second success handler');
},
function (response) {
if (response === 999) {
// do something to recover from earlier reject
console.log('recovery action initiated');
} else {
console.log('second fail handler');
}
}
);
def.done(function () {
console.log('done handler');
});
def.reject(999);
</script>
</body>
</html>
&#13;
我知道无法在两个then
处理程序之间插入,它们只是同一个Deferred的两个排队处理程序。