【问题标题】:Break out of while loop with Async/Await使用 Async/Await 跳出 while 循环
【发布时间】:2020-08-03 12:23:24
【问题描述】:

上下文: 我有一个 while 循环,我想运行 10 次,并且在其中我有每 3 秒运行一次的异步/等待代码。如果 while 循环运行了 10 次并且 async/await 检查没有返回预期值,那么它就像超时一样工作,然后退出 while 循环进程超时。

问题:代码的跳出循环部分首先运行,i(循环变量)的值已达到最大值。当我想出我设置它的方式时,我无法访问 i while 循环的值,只有当 i 处于其最大值时。

问题:当条件满足或者我已经筋疲力尽时,我怎样才能尽早退出这个循环?

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;
        }
    }

注意:如果有人想知道eel.is_authenticated()(); 不是拼写错误,它是一个用于创建桌面应用程序的 python 库,双 ()() 是正常的。

此外,如果这种方法的作用过于复杂,欢迎使用任何其他方法:)

谢谢

【问题讨论】:

    标签: javascript while-loop async-await break


    【解决方案1】:

    这里的问题是您正在立即运行所有循环迭代(10 次),在此过程中设置了 10 个超时,彼此相隔 3 秒:

    1. 您的循环运行 10 次,产生 10 次超时
    2. 您到达i === 9 案例
    3. 3 秒后,第一次超时运行
    4. 3 秒后,第二次超时运行
    5. ...

    您想要的是让循环在迭代之间实际等待 3 秒。为此,您将以不同的方式使用 setTimeout - 您将创建一个在超时时解决的承诺和 await 该承诺:

    // 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');
    

    这里的一个结果是,如果调用 is_authenticated 需要大量时间,则检查间隔将更多超过 3 秒,因为我们现在正在等待 3 秒 和 这个电话。如果这是不希望的,我们可以根据自上次调用以来经过的时间来减少延迟时间:

    // 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');
    

    所有这些都假设这段代码所在的函数是async。如果不是,您需要将其设为async,但您需要记住在调用它时添加.catch(e =&gt; handleTheErrorSomehow(e)),以避免未处理的承诺拒绝!

    【讨论】:

    • 非常感谢或详细说明。我回家后会尽快测试。
    • 代码完美无瑕地工作,非常感谢帮助我并教会了我一些新东西。干杯! :)
    猜你喜欢
    • 2016-12-30
    • 2016-02-04
    • 1970-01-01
    • 2019-07-16
    • 1970-01-01
    • 2022-10-04
    • 1970-01-01
    • 2021-08-31
    • 2020-05-30
    相关资源
    最近更新 更多