【问题标题】:Using setInterval() to do simplistic continuous polling使用 setInterval() 进行简单的连续轮询
【发布时间】:2012-01-30 17:49:40
【问题描述】:

对于需要以设定的时间间隔刷新呈现给用户的部分数据的简单 Web 应用,仅使用 setInterval() 从端点获取 JSON 而不是使用适当的轮询框架有什么缺点吗?

为了举例,假设我每 5 秒刷新一次处理作业的状态。

【问题讨论】:

  • 我会使用setTimeout 并且总是在收到之前的响应时调用它。这样可以避免可能的拥塞或函数堆叠或任何你想调用的东西。
  • 我就像@FelixKling 所说的那样完成了它,并且像魅力一样工作。试试看!
  • 太棒了! @FelixKling,您能否将其发布为答案,我会接受吗?

标签: javascript ajax setinterval polling


【解决方案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);

【讨论】:

  • 这里很好地分析了为什么避免setInterval 是个好主意:weblogs.asp.net/bleroy/archive/2009/05/14/…
  • 我们应该使用setTimeout(refresh, 5000); 两次吗?我的意思是在第一次调用之后,然后在被调用的函数中再次调用?
  • @David,这是因为 setTimeout 不会在间隔内重复:它会在第二个参数中的时间量到期后触发传入其第一个参数的函数一次(实际上是函数之后的那个时间被推入偶数队列,但我离题了。)因此,您需要两个调用:第一个调用启动函数,第二个重复直到完成。
  • 为什么不在递归rerfresh()中调用clearTimeout()?
  • @danielgi:有什么意义?当时refresh 被称为超时是“完成”。没有什么要清除的。
【解决方案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)

【讨论】:

  • 好。作品。例如,如果一段时间后我决定通过单击按钮来停止执行,请问我该怎么做?
  • @Marcel 谢谢。简短的回答是这是不可能的 (stackoverflow.com/a/29479435/1054423)。
【解决方案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 的做事方式中,我认为我可以改进它。您可能需要考虑类似于what's described here 的解决方案,称为长轮询。或者另一种解决方案是 WebSockets(WebSockets 的更好实现之一,其主要目标是在所有浏览器上工作)socket.io

    第一个解决方案基本上概括为您发送一个 AJAX 请求并等待响应,然后再发送一个附加请求,然后一旦响应已交付,就将下一个查询排队。

    同时,在后端您不会返回响应,直到状态发生变化。因此,在您的场景中,您将使用一个 while 循环,该循环将一直持续到状态更改,然后将更改的状态返回到页面。我真的很喜欢这个解决方案。正如上面链接的答案所示,这就是 facebook 所做的(或至少在过去所做的)。

    socket.io 基本上是 Websockets 的 jQuery,因此无论您的用户在哪个浏览器中,您都可以建立一个可以将数据推送到页面的套接字连接(根本不需要轮询)。这更接近于 Blackberry 的即时通知,如果您想要即时通知,这是最好的解决方案。

    【讨论】:

    • 虽然 socket.io 可能不错,但它不是 websockets 的解决方案,只是众多解决方案中的一个。所有这些(几乎)都有自己的优点,您可能会根据要解决的任务考虑不同的框架。
    • 粗心,更新反映提socket.io的意图
    【解决方案5】:

    只要修改@bschlueter's 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....")

    【讨论】:

      猜你喜欢
      • 2016-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多