问题
I have the following code -
this.storeNameValidate = function(stores) {
var deferred = $q.defer();
console.log(stores);
for (storeIndex in stores) {
this.nameValidate(stores[storeIndex].storeName, 3, 10)
.then(function() {
console.log("valid store name");
}, function() {
console.log("invalid store name");
deferred.reject("invalid store name");
})
}
return deferred.promise;
}
I need to break out off the for loop if the nameValidate error block is called. How can i do this ?
I can do it something like this using flagging
this.storeNameValidate = function(stores) {
var deferred = $q.defer();
var flag = false;
console.log(stores);
for (storeIndex in stores) {
this.nameValidate(stores[storeIndex].storeName, 3, 10)
.then(function() {
console.log("valid store name");
var flag = true;
}, function() {
var flag = false;
console.log("invalid store name");
deferred.reject("invalid store name");
})
if (!flag)break;
}
return deferred.promise;
}
Is their some better way ?
回答1:
You should use $q.all with array of promises and return combined promise. This single promise will reject if one of the inner promises fails.
this.storeNameValidate = function (stores) {
var promises = Object.keys(stores).map(function(storeIndex) {
return this.nameValidate(stores[storeIndex].storeName, 3, 10).then(function () {
console.log("valid store name");
}, function () {
return $q.reject("invalid store name");
});
}, this);
return $q.all(promises);
};
Also, don't abuse $q.defer
you don't need it in your case. Such a redundant usage of it is known as deferred anti-pattern.
Also, if error message you are going to reject with is always "invalid store name" (not store specific) and you don't really need to preform additional actions on validated stores, you can omit error and success callbacks all together too. Then the code will become even cleaner:
this.storeNameValidate = function (stores) {
var promises = Object.keys(stores).map(function(storeIndex) {
return this.nameValidate(stores[storeIndex].storeName, 3, 10);
}, this);
return $q.all(promises);
};
回答2:
You are misunderstanding what is going on. Your for loop exits way before anything else happens. It just set's up all the calls, and then they all start running async. What you should do instead is keep (for example) a global variable called "stop" and set it to "true" if the validate error is called. So then in the normal success handler, you can check if stop is true, and if so, don't do anything else.
Really, there are correct ways of handling it, and you should study many promise examples, and you'll see how they do things like "reject" promises, and do "when all", "when any". You will definitely want to get a clear picture of what's happening with very simple examples, and it will serve you well.
回答3:
use a global variable and test it every iteration, if it set to true
then break from the loop:
var isCalled = false;
this.storeNameValidate = function(stores) {
var deferred = $q.defer();
console.log(stores);
for (storeIndex in stores) {
if(isCalled){break;} // break if the callback invoked
this.nameValidate(stores[storeIndex].storeName, 3, 10)
.then(function() {
console.log("valid store name");
isCalled = true;
}, function() {
console.log("invalid store name");
deferred.reject("invalid store name");
isCalled = true;
})
}
return deferred.promise;
}
来源:https://stackoverflow.com/questions/31801982/break-out-of-promise-block-in-a-for-loop