Как выполнить простую операцию переключения в JavaScript с помощью setInterval()?

#javascript

Вопрос:

Вот как выглядит мой код:

 var fnInterval = setInterval(function() {
  let b = true
  if (b) {
    console.log("hi")
  } else {
    console.log("bye")
  }
  b = !b
}, 1000);

clearTimeout(fnInterval, 10000) 

Я новичок в JavaScript, и моя цель здесь-регистрировать сообщение в консоли каждые 1 секунду общей продолжительностью 10 секунд, но в течение каждого интервала я хочу, чтобы мое сообщение переключалось между «привет» и «пока» . Как я могу это сделать? (на данный момент он отображает значение логического значения по умолчанию и не изменяется позже)

Комментарии:

1. Лучше всего использовать анимационные кадры.

Ответ №1:

Переместите переменную флага из функции:

 let b = true;

const fnInterval = setInterval(function() {
    if (b) {
        console.log("hi");
    } else {
        console.log("bye");
    }
    b = !b
}, 1000); 

Чтобы остановить таймер через 10000 миллисекунд, оберните вызов clearInterval в setTimeout :

 setTimeout(() => clearInterval(fnInterval), 10000);
 

Между тем, обратите внимание, что возвращаемое значение setInterval -это не функция, а число, поэтому его вызов может ввести в заблуждение fnInterval .

Ответ №2:

Прежде всего, объявите let b = true вне функции обратного вызова. В противном случае он повторно инициализируется при каждом вызове.

Во-вторых, 10000 в clearTimeout(fnInterval, 10000) не является допустимым параметром. clearTimeout(timeoutId) принимает только первый параметр и немедленно удаляет время ожидания, переданное. Вам понадобится a setTimeout , чтобы запустить это через 10 секунд, если это ваша цель. Но это вызывает состояние гонки между двумя тайм-аутами-неточность может означать, что вы пропустите некоторые журналы или получите дополнительные журналы.

Использование счетчика-это одно из решений, как показывают другие ответы, но обычно, когда я использую сложную синхронизацию setInterval , для которой требуется очистить ее после некоторого количества итераций, я перестраиваюсь на общую обещанную sleep функцию на основе setTimeout . Это делает вызывающий код намного чище (без обратных вызовов) и позволяет избежать возни с clearTimeout ним .

Вместо логического значения для переключения флага туда и обратно между двумя сообщениями лучшим решением является использование массива и модуль текущего индекса по длине массива сообщений. Это значительно облегчает добавление большего количества элементов для циклического просмотра, а код легче понять, поскольку состояние неявно указано в счетчике.

 const sleep = ms => new Promise(res => setInterval(res, ms));

(async () => {
  const messages = ["hi", "bye"];
  
  for (let i = 0; i < 10; i  ) {
    console.log(messages[i%messages.length]);
    await sleep(1000);
  }
})(); 

Ответ №3:

setInterval() это clearInterval() не останавливает clearTimeout() . Подробности прокомментированы в приведенном ниже коде.

 // Define a counter
let i = 0;
// Define interval function
const fnCount = setInterval(fnSwitch, 1000);

function fnSwitch() {
  // Increment counter
  i  ;
  // if counter / 2 is 0 log 'HI'
  if (i % 2 === 0) {
    console.log(i   ' HI');
    // Otherwise log 'BYE'
  } else {
    console.log(i   ' BYE');
  }
  // If counter is 10 or greater run fnStop()
  if (i >= 10) {
    fnStop();
  }
};

function fnStop() {
  // Stop the interval function fnCount()
  clearInterval(fnCount);
};