【问题标题】:How do I make a Javascript loop wait for existing iteration to finsih before starting the next?如何让 Javascript 循环在开始下一个迭代之前等待现有迭代完成?
【发布时间】:2021-01-30 19:00:16
【问题描述】:

如何让下面的循环在开始下一次迭代之前等待当前迭代完成?

var minute = 0

alert ("Kick Off");

var refreshIntervalId = setInterval(function() {     
  if (minute < 91) {
    // lots of code with Ajax calls
    // can take from a fraction of a second to 30 seconds to run code
    // depending on conditions
  } else {
    clearInterval(refreshIntervalId);
  } 
  minute++         
}, 1000);

我通常在先决条件代码完成后使用函数和“.done”来执行代码。我还使用动画中的函数在动画完成后执行代码。

但是,我无法理解如何让代码等待循环迭代完成。如果我将先决条件代码放入一个函数(循环中的所有代码)然后使用 .done,则只有循环的右括号可以放在“.done”函数中 - 这显然不起作用.

谁能解决这个难题?

【问题讨论】:

  • 使用异步等待
  • 因此,您的问题是您的时间间隔为 1 秒,但该函数中的某些活动可能需要超过 1 秒的时间。正确的?在哪种情况下,您希望将下一个间隔的触发延迟到最后一个间隔完成?但是您仍然需要 90 次迭代,即使其中一次迭代花费的时间超过 1 秒?
  • 从不再使用alert 开始,如果您需要“看到事情发生”,请使用console.log。话虽如此,如果您的代码需要 30 秒才能运行,请将其拆分为离散的步骤,然后将每个步骤设为 async 函数,并使用 await 获取其函数结果,以便 JS 调度程序可以中断执行每次它看到await 并保持响应。此外,对于这样的未知运行时代码,从不使用setInterval。相反,让代码路径的最末端重新触发其代码路径,以便仅在完成后运行“下一次迭代”。
  • 尼尔 W,绝对是的。大多数迭代我需要持续 1 秒,但较长的迭代是重要的,需要设置为更长的时间或等到代码完成。 .
  • 当时我尝试使用变量,但没有奏效。

标签: javascript jquery loops asynchronous wait


【解决方案1】:

您可以在异步函数中创建一个 while 循环并使用 await。在下面的代码中,while 循环在每次迭代时至少等待 2 秒,但最多等待任务所需的时间。

const sleep = time => new Promise(resolve => setTimeout(resolve, time))  

async function main() {
  while (true) {
    console.log("new iteration")
    const task = new Promise((resolve, reject) => {
      // things that take long go here…
      const duration = Math.random()*4000
      setTimeout(() => {
        console.log(`done, task took ${Math.round(duration)}ms`)
        resolve()
      }, duration)
    })
    // wait until task is finished but at least 2 seconds
    await Promise.all([task, sleep(2000)])
  }
}

main()

【讨论】:

  • 感觉就像您实际上并没有阅读提出的问题。这绝不会影响仅在“上一次迭代”完成后运行“下一次迭代”。
  • 我认为@Matthias 成功了!阅读问题,了解用例并提供答案!
  • 谢谢。我会试试看它是否有效。
  • @Mike'Pomax'Kamermans awaits 让任务在循环结束时完成,所以应该没问题 @BenSellars 你不客气 :)
【解决方案2】:

在您的具体情况下,将 Matthias 优雅的投票答案带入生活:

var minute = 0
// reusable function to wait the specified amount of time (1000ms in your case)
const sleep = time => new Promise(resolve => setTimeout(resolve, time))  

alert ("Kick Off");

while (minute < 91)
{
    const processThisMinuteTask = new Promise((res, rej) => {
        // lots of code with Ajax calls
        // can take from a fraction of a second to 30 seconds to run code
        // depending on conditions
        // NOTE: use AWAIT for all Ajax calls
        res();
    });
    // will wait for both:
    // a) your processThisMinuteTask to finsih
    // b) 1000ms to pass
    // So, will mean that this iteration will wait for whichever of those is longest
    await Promise.all([processThisMinuteTask, sleep(1000)]);
    minute++;
}

附:如果您想要做的是提示用户开球即将开始,但在他们确认警报之前不会开始,那么“警报”没有任何问题。

进一步评论“await 是一个保留标识符”,需要将封闭函数声明为 async。

function playMatch() {
   // will fail
   await myOtherFunction();

   // more code
}

需要:

async function playMatch() {
    // will now wait for myOtherFunction to finish before continuing.
    await myOtherFunction();

    // more code
}

【讨论】:

  • 谢谢你们。它看起来像一个绝妙的解决方案。等待最大的那个是完美的。我试过并得到“未捕获的语法错误:等待是保留标识符”。尽管我还没有将 await 用于任何 Ajax 调用,但可能是这样。我需要阅读更多关于等待如何工作的信息。“警报”只是一个占位符,最终将被一个漂亮的弹出窗口取代。虽然我可能因为没有在循环中提及 JQuery 动画长度而搞砸了。 AJAX 调用 lengths.seem 需要 >1 秒,但其 JQuery 动画最多需要 30 秒。
  • await 需要包含在使用 async 声明的函数中。查看更新的答案。另外,请阅读 async / await。但也要阅读 Promises。 async / await 是一种更优雅的处理 Promises 的语法,因此良好的 Promises 工作知识会有所帮助。
  • 你帮了大忙。我已经阅读并从逻辑上讲这一切都说得通。然而。如果我在 var minute = 0 上方添加 'async function play_match(){' 并在 while 循环结束后关闭括号,它将永远等待。甚至不提醒“开始”。
  • 我在想要么'.done' Ajax 调用都需要使用'async' 和'await' 重写(因为它们可能会发生冲突并相互等待),或者我需要在我掌握了它的基本用法之前,只需将 await 与一些更小、更简单的代码一起使用。
  • “await is a reserved identifier”错误已经解决。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-08
  • 2014-07-30
  • 1970-01-01
  • 1970-01-01
  • 2019-03-03
  • 2020-11-18
  • 2019-11-29
相关资源
最近更新 更多