7

I have nodejs app that needs a few infinite loops which call async functions. I was considering implementing the following:

async function execute1() {
   ...do some async work...
}

async function execute2() {
   ...do some async work...
}

setInterval(execute1, 500)
setInterval(execute2, 500)

My concern is that if the async functions will take a long time to complete, the open references will pile up and this can result in a memory crash down the line.

  1. is setInterval the right tool for this job? is there a more suitable tool?
  2. What is the most elegant method to make sure the execute() function will not start if the previous run hasn't return?
3
  • you need to await those async events Commented Feb 11, 2019 at 16:55
  • 1
    You could setTimerOut() within the call, once it completes it will call itself. Commented Feb 11, 2019 at 16:55
  • "I have nodejs app that needs a few infinite loops" Why are infinite loops needed? Why is setInterval() needed? Commented Feb 11, 2019 at 17:02

4 Answers 4

13

setInterval isn't the right tool because it's unaware of promises and can't maintain correct control flow.

It can be async function with infinite loop:

async function execute1() {
  while (true) {
    await new Promise(resolve => setTimeout(resolve, 500));
    // ...do some async work...  
  }
}

execute1();
Sign up to request clarification or add additional context in comments.

3 Comments

How to break out of the while loop?
@guest271314 By using a condition instead of true.
FWIW One pattern that used for a condition to achieve breaking the loop let done; while ((done = await new Promise(resolve => ..}).then(() => return !done}))) Why does assignment using await within while expression not retain assigned value?. And a verbose approach based on the former pattern Run multiple recursive Promises and break when requested
4

setTimeout might work better in this case.

async function execute1(delay) {
   // await ...
   setTimeout(() => execute1(delay), delay)
}
execute1(500)

3 Comments

@messerbill — No, it won't. The answer completely fails to explain how this approach works, but it will run repeatedly.
It will execute once, then call setTimeout to execute again, and then again & again, ...
omg...i missed the call to itself, only read setTimeout....nvm
1

you can use simple flags to indicate whether the previous function is still running

let isRunning = false;

async function execute1() {
   if (isRunning) return;
   isRunning = true

   ...do some async work...

   // make sure to call this whether it succeeds or fails, maybe in a finally block
   isRunning = false
}

setInterval(execute1, 500)

2 Comments

Fair, but I think the setTimeout it likely the easier solution for this one.
May not be obvious to some but if ...do some async work... does not contain any await statements, the if (isRunning) will never execute when isRunning === true.
0

You can create a function that will run your execute1(), then wait for it's completion, then run itself with setTimeout().

function randomSleep() {
  return new Promise(resolve => setTimeout(resolve, Math.random() * 3000));
}

let done = 0;

async function execute1() {
   console.log('Execute 1 started.')
   await randomSleep()
   return 'done'
}

const run = () => {
  execute1().then(result => {
    console.log('Execute 1 ended')
    done++
    console.log(`Done ${done} times.`)
    console.log(`Now waiting for 2 seconds`)
    setTimeout(() => {
      run()
    }, 2000)
  })
}

run()

1 Comment

Tested this in node.js. Shouldn't it work withour the randomSleep part? When removing that part this does not wait for the execute1() to finish.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.