我在jquery里面的deferred()方法周围遇到了麻烦。我花了几个小时阅读文档,但我仍然不完全理解我在做什么。
我的基本问题是,我有一系列函数(不是ajax调用),我想按顺序运行,但如果其中任何一个出错,请停止所有进程。
这是我已经走了多远(我已经删除了一堆不需要的代码,只是离开了基本想法)
//The module var myModule = (function() {
//Defaults
var vOne;
var VTwo;
var deferred = $.Deferred();
//Private method
var _myPrivateFunction1 = function(userID) {
if(userID >= 10) {
//All is good, set var vOne to true and run next function
vOne = true;
return deferred.promise();
} else {
//User is not allowed, stop everything else and show the error message
return deferred.reject();
}
}
var _myPrivateFunction2 = function() {
if(vOne === true) {
//Ok we can keep going
return deferred.promise();
} else {
//again stop everything and throw error
return deferred.reject();
}
};
var _myPrivateFunction3 = function(element) {
//...and so on
};
var _errorMsgFunction = function(msg) {
$.log("There was an error: " + msg);
return false;
};
//Public method
var myPublicFunction = function(element,call) {
//element is jquery object passed through user "click" event
var userID = element.data('id')
var userAction = element.data('action');
//Now... i want to fire _myPrivateFunction1, _myPrivateFunction2, _myPrivateFunction3 in sequence and STOP all processes, and run
// _errorMsgFunction if there is an error in any of them.
//This is how far I've gotten...
_myPrivateFunction1(userID).then(_myPrivateFunction2(userAction), _errorMsgFunction("Error in _myPrivateFunction2")).then(_myPrivateFunction3(element),_errorMsgFunction("Error in _myPrivateFunction3")).fail(_errorMsgFunction("Error in _myPrivateFunction1"));
};
// Public API
return {
myPublicFunction: myPublicFunction
};
})();
所以现在我一直得到“_myPrivateFunction2中的错误”(我为了测试目的而强迫这个错误),但是继续开火之后的其他功能......他们不会停止。我在这里缺少什么?
答案 0 :(得分:2)
您无法共享延迟对象。您应该为每个函数的延迟创建一个不同的promise。
这是一个非常简单的例子,为了简单起见使用sycnhronus函数,尽管promises旨在与异步函数一起使用:
var func1 = function(arg){
var dfd = jQuery.Deferred();
if (arg === 0) {
dfd.resolve('func1 Ok');
} else {
dfd.reject('func1 arg != 0');
}
return dfd.promise();
}
var func2 = function(arg){
var dfd = jQuery.Deferred();
if (arg === 0) {
dfd.resolve('func2 Ok');
} else {
dfd.reject('func2 arg != 0');
}
return dfd.promise();
}
var func3 = function(arg){
var dfd = jQuery.Deferred();
if (arg === 0) {
dfd.resolve('func3 Ok');
} else {
dfd.reject('func3 arg != 0');
}
return dfd.promise();
}
如果函数不依赖于其他函数进行处理,我们可以使用jQuery.when
// Parallel processing
jQuery.when(func1(1), func2(0), func3(0)).then(function(res1, res2, res3){
console.log(res1, res2, res3);
}).fail(function(reason){
console.error(reason); // will fail with reason func1 arg != 0
});
如果是序列处理(因为我认为你的问题是),你应该这样做:
// Sequential processing
func1(0).then(function(res1){
return func2(res1);
}).then(function(res2){
return func3(res2);
}).then(function(res3){
// everything ran ok, so do what you have to do...
}).fail(function(reason){
console.log(reason);
});
上面的代码会失败,原因是:
> func2 arg != 0
如果你要进行混合并行和顺序处理,那么你应该混合两种方法。
在我的例子中,如果func1
或func2
有副作用,它们将不会在fail()
内自行撤消。
最佳做法是在您完全确定一切正常时,即在最后then()
次来电时,只有副作用。
答案 1 :(得分:1)
您需要在每个函数中单独使用$.deferred()
,因为您希望为每个函数返回唯一的承诺。
//Private method
var _myPrivateFunction1 = function(userID) {
var deferred = $.Deferred();
if(userID >= 10) {
//All is good, set var vOne to true and run next function
vOne = true;
deferred.resolve();
} else {
//User is not allowed, stop everything else and show the error message
deferred.reject();
}
return deferred.promise();
}
然后你的公共职能应该有效。