-->

Using setInterval() to do simplistic continuous po

2020-02-08 03:56发布

问题:

For a simple webapp that needs to refresh parts of data presented to the user in set intervals, are there any downsides to just using setInterval() to get a JSON from an endpoint instead of using a proper polling framework?

For the sake of the example, lets say I'm refreshing status of a processing job every 5 seconds.

回答1:

From my comment:

I would use setTimeout [docs] and always call it when the previous response was received. This way you avoid possible congestion or function stacking or whatever you want to call it, in case a request/response takes longer than your interval.

So something like this:

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

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


回答2:

A simple non-blocking poll function can be implemented in recent browsers using 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:

You can do just like this:

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:

I know this is an old question but I stumbled over it, and in the StackOverflow way of doing things I thought I might improve it. You might want to consider a solution similar to what's described here which is known as long polling. OR another solution is WebSockets (one of the better implementations of websockets with the primary objective of working on all browsers) socket.io.

The first solution is basically summarized as you send a single AJAX request and wait for a response before sending an additional one, then once the response has been delivered, queue up the next query.

Meanwhile, on the backend you don't return a response until the status changes. So, in your scenario, you would utilize a while loop that would continue until the status changed, then return the changed status to the page. I really like this solution. As the answer linked above indicates, this is what facebook does (or at least has done in the past).

socket.io is basically the jQuery of Websockets, so that whichever browser your users are in you can establish a socket connection that can push data to the page (without polling at all). This is closer to a Blackberry's instant notifications, which - if you're going for instant, it's the best solution.



回答5:

Just modify @bschlueter's answer, and yes, you can cancel this poll function by calling 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....")