1

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();
Jay Bienvenu
  • 3,069
  • 5
  • 33
  • 44
  • [https://github.com/kriskowal/q](https://github.com/kriskowal/q) – Code Spirit Sep 24 '16 at 18:35
  • 1
    @CodeSpirit [Native Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). – Jonathan Lonowski Sep 24 '16 at 18:38
  • What have you been able to figure out so far? Can you share a snippet from an attempt you've made? (Stack Overflow isn't a code writing service. There is an expectation here that you have put in some of your own effort first.) – Jonathan Lonowski Sep 24 '16 at 18:40
  • I've tried working out a solution with `setTimeout` and `setInterval`/`clearInterval`. I tried the method of calling `setInterval` recursively, like so: var retriesMade = 0; var check = () => { if (condition) { return true; } if (retriesMade < retriesAllowed) { throw new Error(); } ++retriesMade; setTimeout(check,1000); },1000); This doesn't actually wait for the condition to be true before moving on. – Jay Bienvenu Sep 24 '16 at 18:49
  • And yes, I have tried to work this out for over an hour now, both through coding and searching for answers in both SO and Bing. I create a new question on SO only when I have failed to find a solution in a timely manner. I'm not looking for someone to write code for me; I'm looking for a pattern to solve my problem and so far have failed to find that pattern. – Jay Bienvenu Sep 24 '16 at 18:52
  • @JayBienvenu Please edit your question to include what you posted in your 1st comment. It adds relevant details and would be easier to read formatted within the post vs. as a comment. – And, my comment about "code writing service" was trying to convince you to expand on your question, hopefully increasing its quality. Whether actually the case or not, your question has the appearance of laziness. From our perspective, until your comments, there was no obvious difference between you coming to SO for a handout or asking after the hour of trials you've now mentioned. – Jonathan Lonowski Sep 24 '16 at 19:12
  • What relevant details are missing? What does the code in my first reply add to the question that it is missing? – Jay Bienvenu Sep 24 '16 at 19:38

2 Answers2

3

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)
  );
Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199
0

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.

Example for Angular

eavidan
  • 5,324
  • 1
  • 13
  • 16
  • You can use the q library without angular. $q is just a wrapper for angular. The core library works the same – eavidan Sep 24 '16 at 18:44