跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端

前端实时数据刷新方案:WebSocket、轮询与 Worker 实战

前端实时数据刷新涉及多种技术选型。WebSocket 提供双向长连接,适合高频推送;传统轮询简单易用但资源消耗大,惰性轮询可避免请求堆积;Web Worker 将任务移至后台线程,防止主线程阻塞并应对页面隐藏节流;Periodic Background Sync 基于 Service Worker 实现真正的后台同步;SharedWorker 支持多标签页共享状态。开发者应根据实时性要求、浏览器兼容性及性能影响选择合适的方案。

RefactorPro发布于 2026/4/9更新于 2026/10/2383 浏览
前端实时数据刷新方案:WebSocket、轮询与 Worker 实战

WebSocket 实时推送

WebSocket 建立一次握手后保持永久连接,直到主动关闭。它支持客户端与服务端的双向通信,服务端有新数据时立刻推给前端,实现真正的实时刷新。

// 连接 WebSocket
const ws = new WebSocket('ws://localhost:8080/ws');

// 收到服务端推送的新数据,自动刷新页面
ws.onmessage = (e) => {
  const newData = JSON.parse(e.data);
  renderPage(newData);
};

// 发生错误/关闭处理
ws.onerror = () => {};
ws.onclose = () => {};

轮询方案对比

定时轮询(setInterval)

这是最基础的方案,通过定时器每隔一段时间向服务器发送请求。虽然简单,但如果接口耗时超过定时时间,会导致多个请求堆积,阻塞主线程或造成服务器压力。

// 1. 定义数据请求函数
async function fetchData() {
  try {
    const res = await fetch('/api/your-data-endpoint');
    const data = await res.json();
    updateUI(data); // 更新页面
  } catch (err) {
    console.error('请求数据失败:', err);
  }
}

// 2. 设置定时器,每 3 秒请求一次
const intervalId = setInterval(fetchData, 3000);


 () {
  (intervalId);
}
// 3. 清除定时器(防止内存泄漏)
function
stopPolling
clearInterval

页面离开或不再需要轮询时,必须清除定时器。推荐在 beforeunload 事件中清除。

惰性轮询(setTimeout 递归)

为了解决请求堆积问题,可以使用递归的 setTimeout。规则是:等上一次请求完成(成功或失败)后,再延迟指定时间发起下一次请求。

let timerId = null;

async function polling() {
  try {
    const res = await fetch('/api/your-data-endpoint');
    const data = await res.json();
    updateUI(data);
  } catch (err) {
    console.error('请求失败:', err);
  } finally {
    // 关键:无论成功失败,3 秒后再执行下一次
    timerId = setTimeout(polling, 3000);
  }
}

// 启动轮询
polling();

// 停止轮询
function stopPolling() {
  clearTimeout(timerId);
}
特性setInterval (定时轮询)setTimeout (惰性轮询)
执行逻辑固定时间间隔执行,不受请求耗时影响上一次完成后,延迟固定时间再执行
请求堆积风险高(请求慢时会堆积)低(串行执行,安全)
适用场景短请求、对时序要求不高的简单场景绝大多数业务场景(推荐)

Web Worker 轮询

Web Worker 最大作用是开启一个独立后台线程,不受主线程阻塞、页面切后台也不会被浏览器严重节流,用来做轮询非常稳。

为什么要用 Web Worker?

普通 setInterval 在页面切后台时会被浏览器节流甚至暂停,JS 执行卡顿也会导致定时器不准。Web Worker 拥有独立线程,不会被 DOM 渲染或 JS 阻塞影响,兼容性也极好(IE10+ 及所有现代浏览器)。

Vue2 写法

需要先安装依赖并配置 webpack。

npm install worker-loader -D

vue.config.js 配置:

module.exports = {
  configureWebpack: {
    module: {
      rules: [
        { test: /\.worker\.js$/, use: { loader: 'worker-loader' } }
      ]
    }
  }
}

创建 src/utils/poll.worker.js:

// 后台轮询线程
let timer = null;

self.onmessage = (e) => {
  const { type, interval } = e.data;
  
  if (type === 'start') {
    clearInterval(timer);
    timer = setInterval(async () => {
      try {
        const res = await fetch('/api/notice');
        const data = await res.json();
        self.postMessage({ status: 'success', data });
      } catch (err) {
        self.postMessage({ status: 'error', msg: err.message });
      }
    }, interval);
  }
  
  if (type === 'stop') {
    clearInterval(timer);
  }
};

页面使用(Vue2 示例):

import PollWorker from '@/utils/poll.worker.js';

export default {
  mounted() {
    this.worker = new PollWorker();
    this.worker.onmessage = (e) => {
      console.log('新数据:', e.data.data);
    };
    this.worker.postMessage({ type: 'start', interval: 3000 });
  },
  beforeDestroy() {
    this.worker.postMessage({ type: 'stop' });
    this.worker.terminate();
  }
};

Vue3 + Vite 写法

Vite 内置支持 Web Worker,语法更简洁。

<script setup>
import { onMounted, onUnmounted } from 'vue';
import PollWorker from '@/utils/poll.worker?worker';

let worker = null;

onMounted(() => {
  worker = new PollWorker();
  worker.onmessage = (e) => {
    if (e.data.status === 'success') {
      console.log('后台刷新数据:', e.data.data);
    }
  };
  worker.postMessage({ type: 'start', interval: 3000 });
});

onUnmounted(() => {
  if (worker) {
    worker.postMessage({ type: 'stop' });
    worker.terminate();
  }
});
</script>

注意: Worker 在使用结束后必须销毁,否则会导致内存泄露。

Periodic Background Sync

Periodic Background Sync 基于 Service Worker 运行,不受页面生命周期影响,专门用于后台定时同步数据。它是专为 PWA 设计的 API,完美解决 Worker 销毁和后台轮询失效的问题。

核心机制

  • 注册:在 Service Worker 注册时,指定唯一标签和最小间隔。
  • 调度:浏览器内核接管计时,在设备联网、充电、闲置等低干扰时机触发。
  • 执行:唤醒 Service Worker,触发 periodicsync 事件。
  • 持久化:注册后跨会话生效,直到主动取消。

代码示例

注册(主线程)

navigator.serviceWorker.ready.then(async (registration) => {
  if (!registration.periodicSync) return;
  try {
    // 注册:每 4 小时同步一次
    await registration.periodicSync.register('order-sync', {
      minInterval: 4 * 60 * 60 * 1000
    });
    console.log('周期性同步注册成功');
  } catch (err) {
    console.error('注册失败', err);
  }
});

监听与执行(Service Worker)

// sw.js
self.addEventListener('periodicsync', (event) => {
  if (event.tag === 'order-sync') {
    event.waitUntil(
      fetch('/api/order/sync')
        .then(res => res.json())
        .then(data => {
          return caches.open('order-cache').then(cache => {
            return cache.put('/api/order/latest', new Response(JSON.stringify(data)));
          });
        })
        .catch(err => console.error('同步失败', err))
    );
  }
});

限制说明:目前 Chrome、Edge 支持较好;Firefox、Safari 暂不支持。需用户授予权限,且触发时间受浏览器策略调整(如电量、网络状态)。

requestIdleCallback

requestIdleCallback(简称 rIC)是浏览器提供的主线程闲时调度 API,专门用来执行非紧急任务,避免长任务卡住渲染。

浏览器每帧约 16ms,如果 JS 执行提前完成,剩余时间就是空闲时段。rIC 回调就在这个时段执行。

const handle = requestIdleCallback((deadline) => {
  while (deadline.timeRemaining() > 0 && taskQueue.length > 0) {
    const task = taskQueue.shift();
    doHeavyWork(task);
  }
  if (taskQueue.length > 0) {
    requestIdleCallback(handle);
  }
}, { timeout: 2000 });

// 取消
cancelIdleCallback(handle);

SharedWorker

SharedWorker 是可以被多个标签页共享的同一个后台线程。相比普通 Worker,它能实现全局轮询和多页同步,避免重复请求。

共享线程文件 shared.worker.js

let timer = null;
let ports = [];

self.onconnect = (e) => {
  const port = e.ports[0];
  ports.push(port);
  
  port.onmessage = (e) => {
    if (e.data === 'start') startPoll();
  };
  port.start();
};

function startPoll() {
  if (timer) return;
  timer = setInterval(async () => {
    const res = await fetch('/api/notice');
    const data = await res.json();
    ports.forEach(port => port.postMessage(data));
  }, 3000);
}

页面中使用

const worker = new SharedWorker('/shared.worker.js');
const port = worker.port;
port.start();

port.onmessage = (e) => {
  console.log('新消息:', e.data);
};

port.postMessage('start');

目录

  1. WebSocket 实时推送
  2. 轮询方案对比
  3. 定时轮询(setInterval)
  4. 惰性轮询(setTimeout 递归)
  5. Web Worker 轮询
  6. 为什么要用 Web Worker?
  7. Vue2 写法
  8. Vue3 + Vite 写法
  9. Periodic Background Sync
  10. 核心机制
  11. 代码示例
  12. requestIdleCallback
  13. SharedWorker

更多推荐文章

查看全部
  • Web 自动化测试入门:核心概念与 Selenium 实战指南
  • 基于 Trae IDE 实现 Figma 设计稿自动转前端代码
  • Java 开发高频 Linux 命令实战:排查、部署与运维
  • cJSON 1.7.19 源码深度分析:数据结构与解析实现
  • C++ STL 排序及相关操作详解
  • C++ STL 详解:list 容器底层实现分析
  • Redis Hash 数据类型及相关指令详解
  • HarmonyOS Stage 模型详解:从架构演进到实战落地
  • C++26 constexpr 重大突破:编译时计算优化方案
  • 小巧的 MCPHost:命令行通过大模型与外部工具交互
  • C++ ROS 回调函数中的对象生命周期陷阱:Use-After-Free 解析
  • 无人机光伏巡检:低空经济下的运维革新与实战
  • Dubbo 发展历程:从阿里内部工具到云原生分布式框架
  • 预训练语言模型与 BERT 实战应用
  • 生物医学Go编程:高性能计算与精准医疗案例分析 (一)
  • Prometheus 核心函数实战:指标处理与聚合技巧
  • C++26 契约编程落地实践与系统异常治理
  • 拆解 Linux 中的 IP 协议与数据链路层:地址、路由与分片的底层逻辑
  • LeetCode 141 环形链表判断:哈希表与快慢指针解法
  • Robot Lab 基于 Isaac Lab 的机器人强化学习实战指南

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online