Reputation: 3293
How do I code this algorithm as a promise in JavaScript?
// condition: some situation that is not true
// interval: period to wait before trying again
// retriesAllowed: maximum number of retries to make before aborting
// retriesMade: number of retries made so far
while() {
if (condition) return true; // indicates success
if (retriesMade < retriesAllowed) return false; // or throw an exception
++retriesMade;
wait(interval);
}
This doesn't work, since it doesn't actually wait for the check to resolve to true or false before moving on:
var check = () => {
if (condition) return true; // indicates success
if (retriesMade < retriesAllowed) return false; // or throw an exception
++retriesMade;
setTimeout(check,interval)
}
check();
Upvotes: 1
Views: 578
Reputation: 123463
This doesn't work, since it doesn't actually wait for the check to resolve to true or false before moving on.
One part of that may be that the fail/exit condition seems to be inversed, so it will probably always exit after the 1st round of checking the condition
:
// retriesMade starts at 0, which is likely already less-than retriesAllowed
if (retriesMade < retriesAllowed) return false;
// probably should be
if (retriesMade >= retriesAllowed) return false;
Beyond that, the lack of waiting is by design with asynchronous operations, such as setTimeout()
waiting out the given delay interval. Surrounding code will always continue to execute without waiting for their result.
Instead of expecting them to wait, you'll need to establish a way to be informed when the process has actually completed and carry on from that information. Promises are one option for that.
Side note: A thorough explanation of the behavior and other options are provided in "How do I return the response from an asynchronous call?"
With them, in place of using return
or throw
, they provide resolve()
and reject()
functions that signal success or failure, respectively, when invoked. Their .then()
and .catch()
methods can be used to setup continuations.
var tries = new Promise((resolve, reject) => {
var retriesMade = 0;
var interval = 1000;
var check = () => {
if (condition) { resolve(); }
if (retriesMade >= retriesAllowed) { reject(); }
++retriesMade;
setTimeout(check, interval);
});
check();
});
tries.then(
() => console.log('success'),
() => console.log('failure')
);
Also, an alternate version that uses Promises more thoroughly, containing the iteration in a function (untilLimited
) as well as permitting the condition (exitUpon
) to be asynchronous, if needed.
function delay(milliseconds) {
return new Promise(function (resolve) {
setTimeout(resolve, milliseconds);
});
}
function untilLimited(limit, waitTime, exitUpon) {
return Promise.resolve()
.then(exitUpon)
.then(result => {
if (result) return true;
if (!(--limit > 0)) return Promise.reject('Limit exceeded.');
return delay(waitTime)
.then(() => untilLimited(limit, waitTime, exitUpon))
});
}
untilLimited(5, 500, () => false /* condition */)
.then(
(result) => console.log('success', result),
(result) => console.log('failure', result)
);
Upvotes: 3
Reputation: 5564
You could use the q
library (or $q
in angular) to return a deferred object, and in the background run the interval, and if after a few attempts the condition
is not satisfied, reject the promise.
Upvotes: 0