使用setInterval()创建无限异步循环

7

我有一个使用Node.js编写的应用程序,需要一些调用异步函数的无限循环。我正在考虑实现以下内容:

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

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

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

我担心如果异步函数需要很长时间才能完成,那么开放的引用将会积累起来,这可能导致内存崩溃。

  1. setInterval 是合适的工具吗?有没有更合适的工具?
  2. 确保 execute() 函数在前一次运行返回之前不会启动的最优雅方法是什么?

你需要“await”那些异步事件。 - messerbill
1
你可以在调用中使用 setTimerOut(),一旦完成,它将会自我调用。 - Bibberty
我有一个Node.js应用程序,需要一些无限循环。为什么需要无限循环?为什么需要使用setInterval()函数? - guest271314
4个回答

12

setInterval 并不是正确的工具,因为它不了解 promises 并且无法维护正确的控制流。

可以使用带有无限循环的 async 函数:

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

execute1();

如何从 while 循环中跳出? - guest271314
通过使用条件而不是 true - Estus Flask
值得一提的是,有一个用于实现循环中断条件的模式:let done; while ((done = await new Promise(resolve => ..}).then(() => return !done})))。关于为什么在while表达式中使用await赋值不能保留已分配的值,请参考此处. 另外还有一种基于前一种模式的冗长方法,可用于运行多个递归Promise并在请求时中断,具体请参见此处 - guest271314

4

setTimeout在这种情况下可能更有效。

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

3
不,它不会。答案完全没有解释这种方法是如何工作的,但它将会被反复执行。 - Quentin
它将执行一次,然后调用setTimeout再次执行,然后再次执行,以此类推... - gafi
天啊...我错过了调用自身的机会,只读了 setTimeout....算了。 - messerbill

1

您可以使用简单的标志来指示前一个函数是否仍在运行。

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)

公平,但我认为setTimeout可能是更容易的解决方案。 - Bibberty
对于一些人来说可能不太明显,但是如果 ...do some async work... 中没有包含任何 await 语句,当 isRunning === true 时,if (isRunning) 将永远不会执行。 - Patrick Roberts

0
你可以创建一个函数,该函数将运行您的execute1(),等待其完成,然后使用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()


在node.js中测试过了。去掉randomSleep部分不应该也能正常工作吗?但是如果去掉这一部分,它就不会等待execute1()执行完毕。 - Nikolas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接