Jquery 如何恰当地打破承诺链?
基于这里的问题:和公认的答案,我想在某个点上打破承诺链,但还没有找到正确的方法。有这个,但我还是迷路了 以原始问题中的示例代码为例:Jquery 如何恰当地打破承诺链?,jquery,promise,break,chain,Jquery,Promise,Break,Chain,基于这里的问题:和公认的答案,我想在某个点上打破承诺链,但还没有找到正确的方法。有这个,但我还是迷路了 以原始问题中的示例代码为例: Menus.getCantinas().then(function(cantinas){ // `then` is how we chain promises Menus.cantinas = cantinas; // if we need to aggregate more than one promise, we `$.when` re
Menus.getCantinas().then(function(cantinas){ // `then` is how we chain promises
Menus.cantinas = cantinas;
// if we need to aggregate more than one promise, we `$.when`
return $.when(Menus.getMeals(cantinas), Menus.getSides(cantinas));
}).then(function(meals, sides){ // in jQuery `then` can take multiple arguments
Menus.sides = sides; // we can fill closure arguments here
Menus.meals = meals;
return Menus.getAdditives(meals, sides); // again we chain
}).then(function(additives){
Menus.additives = additives;
return Menus; // we can also return non promises and chain on them if we want
}).done(function(){ // done terminates a chain generally.
// edit HTML here
});
如果cantinas.length==0
,我将如何断开链?我不想得到食物,也不想得到添加剂,坦率地说,我想称之为某种“空结果”回调。我试过以下的非常难看的(但有效…)。教我正确的方法。这仍然是一个有效的结果,所以本质上不是“失败”,我会说,只是一个空的结果
var emptyResult = false;
Menus.getCantinas().then(function(cantinas){
Menus.cantinas = cantinas;
if (cantinas.length == 0) {
emptyResult = true;
return "emptyResult"; //unuglify me
}
return $.when(Menus.getMeals(cantinas), Menus.getSides(cantinas));
}).then(function(meals, sides){
if (meals == "emptyResult") return meals; //look at my ugliness...
Menus.sides = sides;
Menus.meals = meals;
return Menus.getAdditives(meals, sides);
}).then(function(additives){
if (additives == "emptyResult") return additives;
Menus.additives = additives;
return Menus;
}).done(function(){
if (emptyResult)
//do empty result stuff
else
// normal stuff
});
听起来像你,-你想像往常一样继续完成。承诺的一个很好的特性是,它们不仅可以连锁,而且可以不受限制。在您的情况下,您可以将要“断开”的链的一部分放在if
-语句中:
Menus.getCantinas().then(function(cantinas) {
Menus.cantinas = cantinas;
if (cantinas.length == 0)
return Menus; // break!
// else
return $.when(Menus.getMeals(cantinas), Menus.getSides(cantinas))
.then(function(meals, sides) {
Menus.sides = sides;
Menus.meals = meals;
return Menus.getAdditives(meals, sides);
}).then(function(additives) {
Menus.additives = additives;
return Menus;
});
}).done(function(Menus) {
// with no cantinas, or with everything
});
首先,我认为最好说你正在寻求“绕过”(部分)承诺链,而不是“打破”它
正如你所说,在几个地方测试“emptyResult”是非常难看的。幸运的是,在遵守不执行某些承诺链的相同一般原则的同时,可以使用更优雅的机制
另一种机制是使用承诺拒绝来控制流,然后在链的后面重新检测特定的错误条件,并将其放回成功路径
Menus.getCantinas().then(function(cantinas) {
Menus.cantinas = cantinas;
if(cantinas.length == 0) {
return $.Deferred().reject(errMessages.noCantinas);
} else {
return $.when(Menus.getMeals(cantinas), Menus.getSides(cantinas));
}
}).then(function(meals, sides) {
Menus.sides = sides;
Menus.meals = meals;
return Menus.getAdditives(meals, sides);
}).then(function(additives) {
Menus.additives = additives;
return Menus;
}).then(null, function(err) {
//This "catch" exists solely to detect the noCantinas condition
//and put the chain back on the success path.
//Any genuine error will be propagated as such.
//Note: you will probably want a bit of safety here as err may not be passed and may not be a string.
return (err == errMessages.noCantinas) ? $.when(Menus) : err;
}).done(function(Menus) {
// with no cantinas, or with everything
});
var errMessages = {
'noCantinas': 'no cantinas'
};
从好的方面来说,我发现缺少嵌套有助于提高自然成功路径的可读性。而且,至少对我来说,如果需要的话,这种模式需要最少的脑力杂耍来适应进一步的旁路
另一方面,这种模式的效率略低于Bergi的模式。虽然主路径的承诺数与Bergi路径相同,但cantinas.length==0
路径需要多个承诺数(如果对多个旁路进行了编码,则每个旁路需要一个承诺数)。此外,这种模式需要可靠地重新检测特定的错误条件,因此需要使用errMessages
对象,有些人可能会发现这一点。对于使用内置浏览器承诺的人,如果他们想在不让所有消费者知道拒绝情况的情况下停止承诺链,触发任何链接的然后
或捕获
es或抛出任何未捕获(承诺)
错误,您可以使用以下方法:
var noopPromise = {
then: () => noopPromise,
catch: () => noopPromise
}
function haltPromiseChain(promise) {
promise.catch(noop)
return noopPromise
}
// Use it thus:
var p = Promise.reject("some error")
p = haltPromiseChain(p)
p.catch(e => console.log(e)) // this never happens
基本上,noopPromise是一个基本的存根承诺接口,它接受链接函数,但从不执行任何函数。这取决于这样一个事实,即浏览器显然使用duck类型来确定某个东西是否是承诺,因此YMMV(我在Chrome 57.0.2987.98中测试了这个),但如果这成为一个问题,您可能会创建一个实际的承诺实例,并对其then和catch方法进行中性化。听起来是正确的方法,但当返回菜单时
仍在进行以下所有调用(即。然后(功能(膳食、配餐)
和然后(功能(添加剂)
)。不应进行这些调用,因为没有餐厅
(第一次调用为空)。当返回菜单时,餐点
==菜单
在下面的然后
@DennisG:你需要移动然后
餐点
。它不应该再跟随getCantinas()。然后(…)
,但它应该嵌套在回调中。我希望缩进能让它变得清晰,这看起来正是承诺要避免的回调hell@Yerken:我在这里没有看到任何回调地狱。所有这些函数都返回一些有用的东西。这是正确的解决方案;它与同步版本完全匹配不要误用承诺拒绝。(你不会通过抛出一个任意错误而将其捕获到外部,从而打破一个内部循环,对吗?)内部承诺,外部then
返回可以重构为自己的函数,就像任何其他Javascript重构一样。尽管效率很高,但我实际上更喜欢这种模式。我实际上相信错误对象是有意义的,因为正如您所说,可能还有其他情况。而这个return$.Deferred().reject(errMessages.noCantinas);
在我看来很漂亮,虽然这不是一个“真正的”拒绝,但没关系。我真的应该对return$.Deferred().reject(errMessages.noCantinas)发表评论
-类似于//绕过拒绝
。您可以放心地理解该模式,而无需注释。另请参阅极好的答案,谢谢。它也可以在node中工作——我们的团队在V8中依赖此ducktyping行为,并与Waterline项目的wait
相结合。为了模拟早期回报,我们已经启动了e正在尝试一些更复杂的选项,但这是一个很好的线索!今晚我将对此进行研究。如果我发现任何问题(例如内存泄漏),我会尽量记得向你汇报,但如果你或其他人好奇,而我没有跟进,请随时在这里提醒我。这是一个很好的解决方案。比假装错误或嵌套承诺链要好得多。谢谢!