0

I am trying to make a form a repeating function that will allow me to pass in most functions and rerun the function x times unless a truth response is returned.

A demonstration of the idea is here.

It works, but it returns after the then statement.

I think the issue is with the fact there is asyncs in asyncs i.e.

async a( async b( c ())

const repeatAttempts = async (func, args, attempts) => {
    try {
        let temp_interval = setInterval(function () {
            attempts -= 1;
            const function_response = func.apply(null, args)
            if (function_response) {
                console.log("function_response! = ", function_response);
                console.log("attempts! = ", attempts);
                clearInterval(temp_interval);
                return function_response
            }
            if (attempts < 1) {
                throw "Out of attempts"
            }

        }, 100);
    } catch (error) {
        console.error(error);
        return undefined;

    }
}




q = document.querySelector.bind(document)



repeatAttempts(q, ['dt'], 3).then((c) =>{console.log("then =",c)})
<div><dl>
  <dt><code>thisArg</code></dt>
  <dd>
    <p>The value of <code>this</code> provided for the call to <code>func</code>.</p>
    <p>Note that <code>this</code> may not be the actual value seen by the method: if the method is a function in <a href="/en-US/docs/Web/JavaScript/Reference/Strict_mode">non-strict mode</a> code, <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/null"><code>null</code></a> and <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined"><code>undefined</code></a> will be replaced with the global object, and primitive values will be boxed. This argument is required.</p>
  </dd>
  <dt><code>argsArray</code> <span class="badge inline optional">Optional</span></dt>
  <dd>
    <p>An array-like object, specifying the arguments with which <code>func</code> should be called, or <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/null"><code>null</code></a> or <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined"><code>undefined</code></a> if no arguments should be provided to the function.</p>
    <p>Starting with ECMAScript 5 these arguments can be a generic array-like object instead of an array. See below for <a href="#browser_compatibility">browser compatibility</a> information.</p>
  </dd>
</dl></div>
beautysleep
  • 153
  • 1
  • 9
  • 1
    _"It works, but it doesn't return correctly"_ - So, it doesn't work... -> _"**Describe the problem.** "It doesn't work" isn't descriptive enough to help people understand your problem. Instead, tell other readers what the expected behavior should be. Tell other readers what the exact wording of the error message is, and which line of code is producing it."_ (from [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask)) – Andreas Sep 20 '21 at 11:26
  • 2
    It's the callback to `setInterval` that's executed later, because that's exactly its purpose. Throwing or returning in the `setInterval` callback will also not do anything here. One thing you could do is look into using a promise-based version of setTimeout. – Evert Sep 20 '21 at 11:27

1 Answers1

0

As Evert said, the setInterval needed to be a promise-based version of setTimeout.

And thanks to this answer we now have a very sexy function.

const repeatAttempts = async (func, args, attempts) => {
    try {
        return waitUntil(func.apply(null, args), attempts)
    } catch (error) {
        console.error(error);
        return undefined;

    }
}


async function waitUntil(condition, left) {
  return await new Promise(resolve => {
    const interval = setInterval(() => {
      if (condition || left<1) {
        resolve(condition);
        clearInterval(interval);
      };left -=1;console.log(left)
    }, 100);
  });
}

q = document.querySelector.bind(document)



repeatAttempts(q, ['iframe'], 20).then((c) =>{console.log("then =",c)})
<div><dl>
  <dt><code>thisArg</code></dt>
  <dd>
    <p>The value of <code>this</code> provided for the call to <code>func</code>.</p>
    <p>Note that <code>this</code> may not be the actual value seen by the method: if the method is a function in <a href="/en-US/docs/Web/JavaScript/Reference/Strict_mode">non-strict mode</a> code, <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/null"><code>null</code></a> and <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined"><code>undefined</code></a> will be replaced with the global object, and primitive values will be boxed. This argument is required.</p>
  </dd>
  <dt><code>argsArray</code> <span class="badge inline optional">Optional</span></dt>
  <dd>
    <p>An array-like object, specifying the arguments with which <code>func</code> should be called, or <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/null"><code>null</code></a> or <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined"><code>undefined</code></a> if no arguments should be provided to the function.</p>
    <p>Starting with ECMAScript 5 these arguments can be a generic array-like object instead of an array. See below for <a href="#browser_compatibility">browser compatibility</a> information.</p>
  </dd>
</dl></div>
beautysleep
  • 153
  • 1
  • 9