Reputation: 4483
Following this example
Dojo FAQ: How can I sequence asynchronous operations?
function doNext(previousValue) {
var dfd = new Deferred();
// perform some async logic; resolve the promise
setTimeout(function () {
var next = String.fromCharCode(previousValue.charCodeAt(previousValue.length - 1) + 1);
dfd.resolve(previousValue + next);
}, 50);
return dfd.promise;
}
var promise = doNext('a');
for (var i = 0; i < 9; i++) {
promise = promise.then(doNext);
}
promise.then(function (finalResult) {
// 'doNext' will have been invoked 10 times, each
// invocation only occurring after the previous one completed
// 'finalResult' will be the value returned
// by the last invocation of 'doNext': 'abcdefghijk'
console.log(finalResult);
});
How do I break out of the loop - i.e. stop processing subsequent doNext function calls when doNext meets a certain criteria - for example stop when the next character is 'd' and return the computed value up to that point?
EDIT: so far I tried using deferred cancel() method, but it just kills the process, and returns nothing.
setTimeout(function () {
var next = String.fromCharCode(previousValue.charCodeAt(previousValue.length - 1) + 1);
if(previousValue + next == 'abc')
dfd.cancel('abc');
else
dfd.resolve(previousValue + next);
}, 50);
Upvotes: 1
Views: 238
Reputation: 664548
You should only use the reduce
(or promise = promise.then(doNext)
) loop approach when you always want to process all the items (or decide synchronously how many you need).
To loop an arbitrary number of times and break out at any step, recursion is the better approach:
function wait(t, v) {
var dfd = new Deferred();
// asynchronously resolve the promise
setTimeout(function () {
dfd.resolve(v);
}, t);
return dfd.promise;
}
function doNext(previousValue) {
var next = String.fromCharCode(previousValue.charCodeAt(previousValue.length - 1) + 1);
return wait(50, previousValue + next);
}
function loop(v, i) {
if (i <= 0) return when(v);
if (v == "abc") return when("abc");
return doNext(v).then(function(r) {
return loop(r, i-1);
});
}
loop('a', 9).then(function (finalResult) {
console.log(finalResult);
});
Upvotes: 1
Reputation: 1387
You could do it by check the value returned from the promise and decide whether to call the async request again or not. It is not like you add a break
in the for
loop. But the result will be what you desire.
All the 9 promise.then
will be called but the doNext
will not be called 9 times. Below is the snippet for the same.
for (var i = 0; i < 9; i++) {
promise = promise.then(function(val){
return val === "abcd" ? val : doNext(val);
});
}
You might think this is not existing the loop. That is because the loop would have completed before the callback function is called. But, instead of calling the async function the callback function will simply return the value. which causes the loop to finish quickly. Below is a link to JSBin where I have increased the timeout and you will see that, initially it will take more time till the desired result is returned and then exits quickly.
https://jsbin.com/qiwesecufi/edit?js,console,output
Another, place you can do the checking, is within the doNext
function itself.
function doNext(previousValue) {
var dfd = new Deferred();
if(previousValue === "abcd")
return previousValue;
// perform some async logic; resolve the promise
setTimeout(function () {
var next = String.fromCharCode(previousValue.charCodeAt(previousValue.length - 1) + 1);
dfd.resolve(previousValue + next);
}, 1000);
return dfd.promise;
}
Hope this was helpful.
Upvotes: 1