简体   繁体   English

使用 Async/Await 跳出 while 循环

[英]Break out of while loop with Async/Await

Context : I have a while loop that i want to run 10 times and within i have async/awaait code that runs every 3 seconds.上下文:我有一个 while 循环,我想运行 10 次,并且在其中我有每 3 秒运行一次的异步/等待代码。 The while loop works as sort of a timeout if it ever runs 10 times and the async/await check doesnt return the expected value then, break out of the while loop the process timed out.如果 while 循环运行了 10 次并且 async/await 检查没有返回预期值,那么它就像超时一样工作,然后退出 while 循环进程超时。

Problem : The break out of loop portion of the code is running first with the value of i(loop variable) maxed out.问题:代码的跳出循环部分首先运行,并且 i(loop variable) 的值已达到最大值。 As i figure the way i have it setup i have no access to the value of i while is looping and only when i is at its max value.当我想出我设置它的方式时,我无法访问 i while 循环的值,只有当 i 处于其最大值时。

Question : How can i escape out of this loop early when condition is met or if i is exhausted?问题:当条件满足或我筋疲力尽时,我如何尽早摆脱这个循环?

var i = 0;

    //Run 10 Times
    while (i < 10) {

        //Run every 3 seconds
        ((i) => {
            setTimeout( async () => {
                isAuthenticated = await eel.is_authenticated()();
                sessionStorage.sessionStatus = JSON.stringify(isAuthenticated);
                console.log('------NEW STATUS-------');
                console.log(JSON.parse(sessionStorage.sessionStatus).authenticated);
                console.log('Inside:' + i);
            }, 3000 * i)
        })(i++);

        //Break out of loop early if condition is met or I is exhausted, but it only runs 1 time and i is always max
        if (i === 9 || JSON.parse(sessionStorage.sessionStatus).authenticated) {
            console.log('Outside:' + i);
            checkStatus('retried');
            break;
        }
    }

NOTE: In case anyone is wondering eel.is_authenticated()();注意:如果有人想知道eel.is_authenticated()(); is not a typo, its a python library to create desktop applications the double ()() is normal.不是错字,它是一个 python 库,用于创建桌面应用程序 double ()() 是正常的。

Also if this approach is overly complicated for what it does, any other ways to approach it are welcome:)此外,如果这种方法的作用过于复杂,欢迎使用任何其他方法来处理它:)

Thanks谢谢

The issue here is that you are running through all your loop iterations immediately (10 times), setting up 10 timeouts in the process, 3s apart from each other:这里的问题是您正在立即运行所有循环迭代(10 次),在此过程中设置 10 个超时,彼此相隔 3 秒:

  1. Your loop runs 10 times, creating 10 timeouts您的循环运行 10 次,产生 10 次超时
  2. You reach the i === 9 case您到达i === 9案例
  3. 3s later, 1st timeout runs 3 秒后,第一次超时运行
  4. 3s later, 2nd timeout runs 3 秒后,第二次超时运行
  5. ... ...

What you want is for the loop to actually wait 3s between iterations.您想要的是循环在迭代之间实际等待 3 秒。 For that, you'd use setTimeout in a different way - you'd create a promise that resolves when the timeout is hit and await that promise:为此,您将以不同的方式使用setTimeout - 您将创建一个 promise 来解决超时问题并await promise:

// As helper function for readability
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

// Your loop
let i;
for (i = 0; i < 10; i++) {
  // Wait 3s
  await delay(3000);

  // Check authentication
  const isAuthenticated = await eel.is_authenticated()();
  sessionStorage.sessionStatus = JSON.stringify(isAuthenticated);
  console.log('------NEW STATUS-------');
  console.log(JSON.parse(sessionStorage.sessionStatus).authenticated);
  console.log('Inside:' + i);

  // Break loop if authenticated
  if (isAuthenticated.authenticated) break;
}

// We were authenticated, or looped 10 times
// Note: Because I moved this outside, i will now actually be 10 if the loop
// ended by itself, not 9.
console.log('Outside:' + i);
checkStatus('retried');

One consequence here though would be that if the call to is_authenticated takes a significant amount of time, the checks will be more than 3s apart, because we are now waiting for 3s and for this call.但是这里的一个结果是,如果对is_authenticated的调用花费大量时间,则检查间隔将超过3 秒,因为我们现在正在等待 3 秒此调用。 If this is undesired, we can reduce the delay time based on how much time elapsed since the last call:如果这是不希望的,我们可以根据自上次调用以来经过的时间来减少延迟时间:

// As helper function for readability
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

// We will save here when the last delay completed, so that the checks are always
// 3s apart (unless the check takes longer than 3s)
// Initially we save the current time so that the first wait is always 3s, as before
let lastIteration = Date.now();

// Your loop
let i;
for (i = 0; i < 10; i++) {
  // Wait until 3s after last iteration (limited to 0ms, negative waits won't work)
  await delay(Math.max(lastIteration + 3000 - Date.now(), 0));

  // Update "last iteration" time so the next delay will wait until 3s from now again
  lastIteration = Date.now();

  // Check authentication
  const isAuthenticated = await eel.is_authenticated()();
  sessionStorage.sessionStatus = JSON.stringify(isAuthenticated);
  console.log('------NEW STATUS-------');
  console.log(JSON.parse(sessionStorage.sessionStatus).authenticated);
  console.log('Inside:' + i);

  // Break loop if authenticated
  if (isAuthenticated.authenticated) break;
}

// We were authenticated, or looped 10 times
// Note: Because I moved this outside, i will now actually be 10 if the loop
// ended by itself, not 9.
console.log('Outside:' + i);
checkStatus('retried');

All of this assumes that the function in which this code is located is async .所有这些都假设此代码所在的 function 是async If it isn't, you need to make it async but then you need to remember adding a .catch(e => handleTheErrorSomehow(e)) when you call it, to avoid unhandled promise rejections!如果不是,您需要将其设为async ,但是您需要记住在调用它时添加.catch(e => handleTheErrorSomehow(e))以避免未处理的 promise 拒绝!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM