Использование setInterval() для упрощенного непрерывного опроса

Для простого веб-приложения, которому нужно обновлять части данных, представляемых пользователю через заданные интервалы, есть ли недостатки в использовании setInterval() для получения JSON из конечной точки вместо использования надлежащей структуры опроса?

Для примера, скажем, я обновляю статус задания обработки каждые 5 секунд.

Ответ 1

Из моего комментария:

Я бы использовал setTimeout [docs] и всегда вызывал его, когда был получен предыдущий ответ. Таким образом, вы избегаете возможной перегрузки или стекирования функций или того, что вы хотите назвать, в случае, если запрос/ответ занимает больше времени, чем ваш интервал.

Так что-то вроде этого:

function refresh() {
    // make Ajax call here, inside the callback call:
    setTimeout(refresh, 5000);
    // ...
}

// initial call, or just call refresh directly
setTimeout(refresh, 5000);

Ответ 2

Простая неблокирующая функция опроса может быть реализована в последних браузерах с использованием Promises:

var sleep = time => new Promise(resolve => setTimeout(resolve, time))
var poll = (promiseFn, time) => promiseFn().then(
             sleep(time).then(() => poll(promiseFn, time)))

// Greet the World every second
poll(() => new Promise(() => console.log('Hello World!')), 1000)

Ответ 3

Вы можете сделать так:

var i = 0, loop_length = 50, loop_speed = 100;

function loop(){
    i+= 1; 
    /* Here is your code. Balabala...*/
    if (i===loop_length) clearInterval(handler);
}

var handler = setInterval(loop, loop_speed);

Ответ 4

Я знаю, что это старый вопрос, но я наткнулся на него, и в способе StackOverflow делать то, что я думал, я мог бы его улучшить. Возможно, вы захотите рассмотреть решение, подобное тому, что описано здесь, которое известно как длительный опрос. Или другое решение - это WebSockets (одна из лучших реализаций веб-сокетов с основной целью работы во всех браузерах) socket.io.

Первое решение в основном суммируется, когда вы отправляете один запрос AJAX и ожидаете ответа перед отправкой дополнительного, а затем, как только ответ был доставлен, поставите в очередь следующий запрос.

Между тем, на бэкэнд вы не возвращаете ответ, пока не изменится статус. Таким образом, в вашем сценарии вы использовали бы цикл while, который будет продолжаться до тех пор, пока статус не изменится, а затем верните измененный статус на страницу. Мне действительно нравится это решение. Как видно из приведенного выше ответа, это то, что делает facebook (или, по крайней мере, в прошлом).

socket.io - это, в основном, jQuery для Websockets, так что любой браузер, в котором находятся ваши пользователи, может установить соединение сокета, которое может выводить данные на страницу (без опроса вообще). Это ближе к мгновенным уведомлениям Blackberry, которые - если вы собираетесь на мгновение, это лучшее решение.

Ответ 5

Просто измените @bschlueter answer, и да, вы можете отменить эту функцию опроса, вызвав cancelCallback()

let cancelCallback = () => {};

var sleep = (period) => {
  return new Promise((resolve) => {
    cancelCallback = () => {
      console.log("Canceling...");
      // send cancel message...
      return resolve('Canceled');
    }
    setTimeout(() => {
      resolve("tick");
    }, period)
  })
}

var poll = (promiseFn, period, timeout) => promiseFn().then(() => {
  let asleep = async(period) => {
    let respond = await sleep(period);
    // if you need to do something as soon as sleep finished
    console.log("sleep just finished, do something...");
    return respond;
  }


  // just check if cancelCallback is empty function, 
  // if yes, set a time out to run cancelCallback()
  if (cancelCallback.toString() === "() => {}") {
    console.log("set timout to run cancelCallback()")
    setTimeout(() => {
      cancelCallback()
    }, timeout);
  }

  asleep(period).then((respond) => {
    // check if sleep canceled, if not, continue to poll
    if (respond !== 'Canceled') {
      poll(promiseFn, period);
    } else {
      console.log(respond);
    }
  })

  // do something1...
  console.log("do something1...");

})


poll(() => new Promise((resolve) => {
  console.log('Hello World!');
  resolve(); //you need resolve to jump into .then()
}), 3000, 10000);

// do something2...
console.log("do something2....")