你以为轮询就是 setInterval?再学学吧!

4,248 阅读2分钟

前两天在写 SSE 文章的时候突然想起来了轮询方案,但是隐约记得轮询也是有区分的,简单回顾一下!

短轮询

原理

  1. 简单的讲短轮询其实就是 setInterval( ) 方法不断地请求后台,以达到实时更新数据的目的。
  2. 比较装*的语言就是:客户端按照固定的时间间隔向服务器发送请求,询问是否有新的数据。无论服务器是否返回了新数据,客户端都会在指定的时间间隔后再次发起请求,形成循环查询的机制。

实现方案

前端直接使用 setInterval 方法反复调用接口即可,当然也有其他方案,但是最终目的大同小异,就是不断地请求后台。

代码

// 客户端
const getMessage = function() {
    setInterval(() => {
        this.$http.get('/queryMessage')
            .then(response => {
                this.message = response.data.message;
            });
    }, 5000); // 每5秒请求一次
}

// 服务端
async function queryMessage() {
    const { ctx } = this;
    // 假设我们有一个方法来获取新消息
    const newMessage = await this.getNewMessage();
    if (newMessage) {
        ctx.body = { message: newMessage };
    } else {
        ctx.body = { message: 'No new messages' };
    }
}

弊端

  1. 不断请求后台接口容易造成资源浪费。
  2. 不管有没有新数据都不断请求效率太低。
  3. 如果后台服务异常,客户端容易不断抛出异常。(这一点我就被客户骂过)

长轮询

原理

长轮询是一种稍微复杂的轮询技术,旨在减少不必要的请求次数。

当客户端发起请求时,如果服务器当前没有新数据,则不是立即返回响应,而是保持这个请求连接打开一段时间,等待新数据的到来。

一旦有新数据或者等待时间超时,服务器就会返回响应给客户端。之后,客户端会立刻发起下一个请求,重复这个过程。

实现方案

  1. 当客户端发起请求的时候,如果服务器没有新数据,当前请求并不立即返回响应,而是将当前请求暂时挂起,等待新数据。
  2. 如果在等待一段时间以后存在数据更新,则立即将数据返回。(这里需要注意客户端接口请求超时时间)
  3. 如果在等待一段时间以后不存在数据更新,则将空数据返回。
  4. 当客户端获得响应后,立即发起下一次请求。

代码

// 客户端
const getMessage = async function () {
    try {
        const response = await this.$http.get('/queryMessage');
        this.message = response.data.message;
    } catch (error) {
        console.error("Error during polling", error);
    }
    getMessage();
}

// 服务端
async function queryMessage() {
    const { ctx } = this;
    let newMessage = null;
    const timeout = 30000; // 设置超时时间
    const startTime = Date.now();

    // 循环等待新消息或超时
    while (!newMessage && Date.now() - startTime < timeout) {
        newMessage = await this.getNewMessage();
        if (!newMessage) {
            await new Promise(resolve => setTimeout(resolve, 1000)); // 等待1秒
        }
    }

    ctx.body = { message: newMessage || 'No new messages within timeout' };
}

弊端

  1. 尽管长轮询减少了客户端频繁发起请求的次数,但每次请求都会占用服务器的一个连接,直到有新数据或超时。在高并发场景下,这可能会导致服务器资源紧张。
  2. 在移动网络环境下,由于网络状态不稳定,长轮询可能导致更多的连接重试,消耗更多电量,并且影响用户体验。

总结

其实无论长轮询或者短轮询只是一种选择,最重要的是选择合适的方案。(最重要的是不要让客户看到报错!!!)

示意图

20250424-长轮询与短轮询.png