Выйти из L oop с Async / Await - PullRequest
0 голосов
/ 20 апреля 2020

Контекст : У меня есть время l oop, которое я хочу запустить 10 раз, и в течение этого времени у меня есть асинхронный / ожидающий код, который запускается каждые 3 секунды. В то время как l oop работает как своего рода тайм-аут, если он когда-либо запускается 10 раз, а проверка асинхронности / ожидания не возвращает ожидаемое значение, затем выйдите из режима ожидания, пока l oop истекло время ожидания процесса.

Проблема : сначала выполняется фрагмент кода l oop с максимальным значением i (переменная l oop). Поскольку я понимаю, как у меня это настроено, у меня нет доступа к значению i, пока оно зацикливается, и только когда i находится на максимальном значении.

Вопрос : Как я могу выйти этого l oop рано, когда условие выполнено или если я исчерпан?

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 для создания настольных приложений функция double () () нормальна.

Также, если этот подход слишком сложен из-за того, что он делает, любые другие подходы к нему приветствуются:)

Спасибо

1 Ответ

3 голосов
/ 21 апреля 2020

Проблема здесь в том, что вы выполняете все свои итерации l oop сразу (10 раз), устанавливая 10 таймаутов в процессе, с интервалом 3 с друг от друга:

  1. Ваш л oop выполняется 10 раз, создавая 10 тайм-аутов
  2. Вы достигаете i === 9 случая
  3. 3 с спустя, 1-й тайм-аут запускается
  4. 3 с позже, 2-й тайм-аут запускается
  5. ...

Вам нужно, чтобы l oop действительно ожидал 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 секунды, потому что сейчас мы ждем 3s и для этого вызова. Если это нежелательно, мы можем уменьшить время задержки, основываясь на том, сколько времени прошло с момента последнего вызова:

// 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 => handleTheErrorSomehow(e)) при вызове, чтобы избежать необоснованного отклонения обещания!

...