0

I have the following code, stripped out of any specifics:

const installation = async() => {
  try {
    const call = await callToServer();
    
    if('finished' in call) {
      return call;
    } else {
      await callToServer();
    }
  } catch(e) {
  //
  }
}

And as you can see, I'd like to recursively call callToServer until I see finished inside its response. I understand why my code isn't working and why it's making only 2 calls (or 1, if it sees finished on the first run), but I don't know how to make it recursive.

I tried with a for loop and, well, it worked as-is, but in my case, I don't know the number of calls I need to make upfront. So I went to a do...while loop, since it seemed to fit:

do {
    const call = await callToServer();
} while(!('finished' in call));

But this only runs once. It sees that the while(!... doesn't actually know about call. How can I make it work?

5
  • 1
    Have a global call variable. So you would create const call outside the do-while loop. Commented Dec 29, 2020 at 9:33
  • 1
    "And as you can see, I'd like to recursively call callToServer" - For recursion something has to call itself again. Nothing in your example does this. So something in installation would have to call installation Commented Dec 29, 2020 at 9:33
  • Note: for is a generic syntax for loops. You don't need to know how many times you need to lop to use for. For example you can do for ( ; condition ; ) ... which will behave exactly the same as while (condition) Commented Dec 29, 2020 at 9:38
  • @slebetman Huh, interesting. Let me see if I can find an "empty for" example or some documentation on that. I had always assumed that a for loop needs to know the number of steps it needs to run for initially. However, if for ( ; condition ; ) is valid syntax, then it's just personal preference over do...while, right? It's just weird to have for( i=0; !finished; i++) for this use-case for me. Commented Dec 29, 2020 at 9:42
  • C programmers have been using for (;;) .. as infinite loop for a long time and it's supported in javascript as well. I've always thought for (;;) .. is a stupid way to do infinite loop because #define ALWAYS 1; while (ALWAYS) .. feels more readable to me. But yeah, for is very flexible Commented Dec 29, 2020 at 10:04

4 Answers 4

6
} else {
  return await installation();
}

A recursive function would call the entire function again.

Sign up to request clarification or add additional context in comments.

2 Comments

you're the only person here to actually address the missing return
Can confirm what @Mulan said - my recursive function kept diving out early until I added the return to my recursive function call.
0

You don't necessarily need recursion, a simple loop will work to recall your callToServer.

You were on the right track with a do...while loop. You might consider putting a limit in on the number of calls before bombing out. The below will attempt 10 times before doing so - it uses a random chance on whether it works or not so you might see it bombing out.

const installation = async() => {
  try {
    var call = null;
    var i = 0
    do {
       console.log("attempt",i++)
       call = await callToServer();
    } while(! ('finished' in call) && i <10 );
    return call;
  } catch(e) {
  //
  }
}

const callToServer = async() => {
  return new Promise(resolve => {
    if(Math.random()>0.95) {
      resolve({finished:true})
    }
    else {
      resolve({notfinished:true})
    }
  })
}

const test = async() => {
  var res = await installation()
  console.log(res)
}

test()

1 Comment

You are right! Someone else gave me this idea of not being stuck to just what's happening inside do and I ended up with a finished flag.
0
  const installation = async() => {
  try {
    const call = await callToServer();
    
    if('finished' in call) {
      return call;
    } else {
      return await installation();
    }
  } catch(e) {
  //
  }
}

1 Comment

This can work and if I could accept a sister answer, I'd accept it, but with this approach, I'm always calling callToServer with the same arguments. Assume I wanted to callToServer with arguments that come from call, I can't do that here and making it work this way would make it more complicated than it needs to be.
0

Notice that using async/await is new syntax in ES that is similar to how generators function* and yield work, so we can do for, while, recursive call for async function in a sync syntax.

Here is an example that do recursive call while the target value is not met yet


let counter = 0;
let res;


function delay(ms){
        return new Promise((res,rej) => setTimeout(res, ms));
}

async function callToServer(){
        await delay(100);
        return ++counter;
}







async function recursive(){

        res = await callToServer();
        console.log(`called server with return value = ${res}`);

        if(res < 10){
                return await recursive();
        }

        return 'RESULT';

}


(async function main(){
                
        let finalRes = await recursive();
        console.log(finalRes);

})()

this code will output:

called server with return value = 1
called server with return value = 2
called server with return value = 3
called server with return value = 4
called server with return value = 5
called server with return value = 6
called server with return value = 7
called server with return value = 8
called server with return value = 9
called server with return value = 10
RESULT

1 Comment

Yup, this works, but : stackoverflow.com/questions/65490027/… / so, while the answer is GOOD for this question specifically, stackoverflow.com/a/65490138/14906201 is more flexible while not trading too much readability away.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.