我有以下内容:
https://jsfiddle.net/qofbvuvs/
var allItems = ["1", "2", "3"]
var allPeople = ["A", "B"]
var testFoo = function(itemValue, peopleValue) {
setTimeout(function(){
return itemValue == "3" && peopleValue == "B"
}, 200)
}
allItems.forEach(function(itemValue) {
allPeople.forEach(function(peopleValue) {
// I want to iterate through each object, completing testFoo before moving on to the next object, without recursion. TestFoo has a few instances of setTimeout. I've tried using promises to no avail.
if (testFoo(itemValue, peopleValue)){
alert("success")
} else{
// nothing
};
})
})
alert("complete")
我的目标是在等待testFoo
的结果的同时,按顺序逐个遍历每个项目。如果testFoo通过,那么我应该停止执行。
我曾尝试使用promises(https://jsfiddle.net/qofbvuvs/2/)但无法获得我正在寻找的行为。 Success
之前应调用Complete
。 TestFoo
有一些我需要解决的setTimeouts(这是一个我无法修改的库)。如何实现这一目标?
答案 0 :(得分:1)
你可以做的一种方法是通过jQuery延迟并手动单步执行数组,而不是使用内置循环,这样你就可以控制是否/何时继续。我猜它在某种程度上使用递归,但仅仅是调用下一次迭代 - 没有疯狂的递归返回值解析或任何使递归复杂的东西。如果这对你有用,请告诉我:
var allItems = ["1", "2", "3"]
var allPeople = ["A", "B"]
var testFoo = function(itemValue, peopleValue) {
var deferredObject = $.Deferred();
setTimeout(function() {
deferredObject.resolve(itemValue == "3" && peopleValue == "B")
}, 200)
return deferredObject;
}
var currentItemIndex = 0;
var currentPeopleIndex = 0;
var testDeferred = $.Deferred();
function testAll() {
testFoo(allItems[currentItemIndex], allPeople[currentPeopleIndex]).done(function(result) {
if (result) {
// found result - stop execution
testDeferred.resolve("success");
} else {
currentPeopleIndex++;
if (currentPeopleIndex >= allPeople.length) {
currentPeopleIndex = 0;
currentItemIndex++;
}
if (currentItemIndex >= allItems.length) {
// result not found - stop execution
testDeferred.resolve("fail");
} else {
// check next value pair
testAll();
}
}
});
return testDeferred;
}
testAll().done(function resolveCallback (message) {
alert(message);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
答案 1 :(得分:1)
由于已经有很多解决方案,我想我会使用async/await
添加解决方案。我个人喜欢这个,因为它保持代码类似于您的原始和更紧凑,您不必跟踪任何中间状态或解决所有承诺。解决方案是将for循环包装在异步函数中,并将forEach更改为(var x ...)的基本,因为await在forEach语句中无法正常工作,因为您正在定义内部非异步函数并调用{{其中1}}无效。另外,更改await
函数以返回承诺。
由于for循环位于函数内部,因此一旦找到匹配项就跳过进一步检查,就可以轻松退出。我还在循环的末尾添加了一个return语句,表示没有找到任何内容,这可能很方便。
最后,由于异步函数本身会返回一个promise,所以您只需在返回的promise的testFoo
内添加最终警报,以评估是否找到了匹配项。
异步/等待示例:
then
&#13;
答案 2 :(得分:0)
使用Promise.all
来解决您的问题。希望这会有所帮助。
var allItems = ["1", "2", "3"];
var allPeople = ["A", "B"];
var testFoo = function(itemValue, peopleValue) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(itemValue === "3" && peopleValue === "B");
}, 200);
});
}
var promises = [];
allItems.forEach(function(itemValue) {
allPeople.forEach(function(peopleValue) {
promises.push(testFoo(itemValue, peopleValue).then(function(result) {
console.log(result?'success':'fail');
return result;
}));
})
});
Promise.all(promises).then(function(results) {
console.log('Result from all promise: ' + results);
console.log("complete");
});
答案 3 :(得分:0)
如果你想构建一个承诺链,其中每个承诺都不会被创建,直到它的链中的前任承诺结算,你应该创建一个函数数组来返回你的承诺并使用简化来创建所需的承诺链。
var allItems = ["1", "2", "3"];
var allPeople = ["A", "B"];
// Async requests aren't made once we reach "2" and "B"
var resultToStopOn = function(itemValue, peopleValue) {
return itemValue === "2" && peopleValue === "B"
}
var testFoo = function(itemValue, peopleValue) {
return new Promise(function(resolve) {
console.log('Starting promise for: ', itemValue, peopleValue);
setTimeout(function() {
console.log('Resolving promise for: ', itemValue, peopleValue);
resolve(resultToStopOn(itemValue, peopleValue));
}, 200);
});
}
var functionsThatReturnPromises = [];
allItems.forEach(function(itemValue) {
allPeople.forEach(function(peopleValue) {
functionsThatReturnPromises.push(function() {
return testFoo(itemValue, peopleValue);
});
});
});
functionsThatReturnPromises
.reduce(function(chainOfPromises, fnReturningAPromise) {
return chainOfPromises.then(function(result) {
// if result is false, we continue down the chain
// otherwise we just propagate the result and don't chain anymore
return !result
? fnReturningAPromise()
: result;
});
}, Promise.resolve())
.then((result) => {
console.log('Result: ', result);
});