发动态
综合 最新发布 最新回复
图文
列表
在做实时监控系统时,比如服务器状态面板、订单处理中心或物联网设备看板,每隔 5 秒自动拉取最新数据是再常见不过的需求了。但你有没有遇到过这些问题?页面切到后台还在疯狂发请求,浪费资源上一次请求还没回来,下一次又发了,接口雪崩用户切换标签页回来,发现数据“卡”在旧状态页面销毁了定时器还在跑,内存泄漏今天我就以一个运维监控平台的真实场景为例,带你从“能用”做到“好用”。一、问题场景:设备在线状态轮询假设我们要做一个 IDC 机房设备监控页,需求如下:每 5 秒查询一次所有服务器的在线状态接口 /api/servers/status 响应较慢(平均 1.2s)用户可能切换到其他标签页处理邮件页面关闭时必须停止轮询如果直接写个 setInterval,很容易踩坑。我们一步步来优化。二、第一版:基础轮询(能跑,但有隐患) import { ref, onMounted, onUnmounted } from 'vue' const servers = ref([]) let timer = null onMounted(() => { const poll = () => { fetch('/api/servers/status') .then(res => res.json()) .then(data => { servers.value = data }) } poll() // 首次立即执行 timer = setInterval(poll, 5000) // 每5秒轮询 }) onUnmounted(() => { clearInterval(timer) // 🔍 清理定时器 }) ✅ 实现了基本功能 ❌ 但存在三个致命问题:接口未完成就发起下一次请求 → 可能雪崩页面不可见时仍在轮询 → 浪费带宽和电量异常未处理 → 网络错误可能导致后续不再轮询三、第二版:可控轮询 + 可见性优化我们改用“请求完成后再延迟 5 秒”的策略,避免并发: import { ref, onMounted, onUnmounted } from 'vue' const servers = ref([]) let abortController = null // 用于取消请求 const poll = async () => { try { // 支持取消上一次请求 abortController?.abort() abortController = new AbortController() const res = await fetch('/api/servers/status', { signal: abortController.signal }) if (!res.ok) throw new Error('Network error') const data = await res.json() servers.value = data } catch (err) { if (err.name !== 'AbortError') { console.warn('轮询失败,将重试...', err) } } finally { // 🔍 请求结束后再等5秒发起下一次 setTimeout(poll, 5000) } } onMounted(() => { poll() // 启动轮询 }) onUnmounted(() => { abortController?.abort() }) 🔍 关键点解析:finally 中 setTimeout 实现“串行轮询”,避免并发AbortController 可在组件卸载时主动取消进行中的请求错误被捕获后仍继续轮询,保证稳定性四、第三版:智能节流 —— 页面可见性控制现在解决“页面不可见时是否轮询”的问题。我们引入 visibilitychange 事件: let isVisible = true const handleVisibilityChange = () => { isVisible = !document.hidden console.log('页面可见性:', isVisible ? '可见' : '隐藏') } onMounted(() => { // 监听页面可见性 document.addEventListener('visibilitychange', handleVisibilityChange) const poll = async () => { try { abortController?.abort() abortController = new AbortController() const res = await fetch('/api/servers/status', { signal: abortController.signal }) const data = await res.json() servers.value = data } catch (err) { if (err.name !== 'AbortError') { console.warn('轮询失败:', err) } } finally { // 🔍 只有页面可见时才继续轮询 if (isVisible) { setTimeout(poll, 5000) } else { // 页面隐藏,等待恢复后再请求 document.addEventListener('visibilitychange', function waitVisible() { if (!document.hidden) { document.removeEventListener('visibilitychange', waitVisible) setTimeout(poll, 1000) // 恢复后1秒再查 } }, { once: true }) } } } poll() }) 🔍 这里做了两层控制:页面隐藏时,不再自动发起下一轮请求页面重新可见时,延迟 1 秒触发一次查询,避免瞬间唤醒过多资源五、封装成可复用的轮询 Hook把这套逻辑抽象成通用 usePolling Hook: // composables/usePolling.js import { ref } from 'vue' export function usePolling(fetchFn, interval = 5000) { const data = ref(null) const loading = ref(false) const error = ref(null) let abortController = null let isVisible = true const poll = async () => { if (loading.value) return // 防止重复执行 loading.value = true error.value = null try { abortController?.abort() abortController = new AbortController() const result = await fetchFn(abortController.signal) data.value = result } catch (err) { if (err.name !== 'AbortError') { error.value = err console.warn('Polling error:', err) } } finally { loading.value = false // 🔍 根据可见性决定是否继续 if (isVisible) { setTimeout(poll, interval) } } } const start = () => { // 移除旧监听避免重复 document.removeEventListener('visibilitychange', handleVisibility) document.addEventListener('visibilitychange', handleVisibility) poll() } const stop = () => { abortController?.abort() document.removeEventListener('visibilitychange', handleVisibility) } const handleVisibility = () => { isVisible = !document.hidden if (isVisible) { setTimeout(poll, 1000) } } return { data, loading, error, start, stop } } 使用方式极其简洁: <script setup> import { usePolling } from '@/composables/usePolling' const fetchStatus = async (signal) => { const res = await fetch('/api/servers/status', { signal }) return res.json() } const { data, loading } = usePolling(fetchStatus, 5000) // 自动在 onMounted 启动 </script> <template> <div v-if="loading">加载中...</div> <ul v-else> <li v-for="server in data" :key="server.id"> {{ server.name }} - {{ server.status }} </li> </ul> </template> 六、对比主流轮询方案方案实现方式优点缺点适用场景setInterval固定间隔触发简单直观不考虑响应时间,易并发快速原型串行 setTimeout请求完再延时避免并发,稳定周期不严格多数业务场景 ✅WebSocket服务端推送实时性最高成本高,兼容性差股票行情、聊天Server-Sent Events单向流式推送轻量级实时不支持 IE日志流、通知智能轮询(本方案)可见性+串行控制节能、稳定、用户体验好略复杂生产环境推荐 ✅ 七、举一反三:三个变体场景实现思路动态轮询频率 如网络异常时降频至 30s 一次,正常后恢复 5s。可在 finally 中根据 error.value 动态调整 setTimeout 时间。多接口协同轮询 多个 API 轮询但希望错峰发送。可用 Promise.all 组合请求,在 finally 统一控制下一轮时机,避免瞬间并发。离线重连机制 当检测到网络断开(fetch 超时),改为指数退避重试(1s → 2s → 4s → 8s),恢复后再切回 5s 正常轮询。小结实现“每 5 秒轮询”看似简单,但要做到稳定、节能、用户体验好,需要考虑:✅ 使用 串行 setTimeout 替代 setInterval,避免请求堆积✅ 利用 AbortController 主动取消无用请求✅ 结合 页面可见性 API 节省资源✅ 封装为 可复用 Hook,提升工程化水平记住一句话:好的轮询,是“聪明地少做事”,而不是“拼命做事情”。下次当你接到“每隔 X 秒刷新”的需求时,别急着写 setInterval,先问问自己:用户真的需要这么频繁吗?能不能用 WebSocket?页面看不见的时候还要刷吗?——转载自:前端微白
如何优雅地实现每 5 秒轮询请求?
开源硬件平台
做电子设备研发、生产的朋友,大概率都遇到过这类难题: 散热器规格拉满,整机散热结构反复优化,可设备运行一段时间依旧烫手;同款元器件,有的批次故障率偏高;户外、车载等复杂环境下,设备寿命远达不到设计标准…… 其实多数时候,问题并非出在散热大件上,而是卡在了热源传递的中间环节。元器件外壳和散热部件无法完全紧密贴合,缝隙里的空气阻断了热量传导,这也是设备降温效果差的核心原因。针对这个行业通病,业内普遍会使用导热硅胶片来化解。 一、导热硅胶片到底好在哪?很多人会把它和普通垫片混为一谈,实际上二者有着本质区别。导热硅胶片主打界面导热,柔软的材质可以被轻微挤压,牢牢填充所有缝隙,把芯片、主板等元器件产生的热量,平稳传递到散热结构上。 同时它自带三大实用特性:一是电气绝缘,有效规避短路风险;二是具备减震缓冲效果,能抵消设备运行中的震动,保护精密元件;三是阻燃耐温,面对高低温交替的复杂工况,性能依旧稳定。而且它安装便捷,无需胶水固定,拆装维护都十分方便。 二、不同行业该怎么选款?1. 3C 数码、智能家居:优先选轻薄款、低析出导热硅胶片,避免污染精密电路板;2. 工控设备、变频器、伺服系统:侧重高绝缘、耐老化款式,适配长时间连续工作;3. 新能源充电桩、车载电子、储能模块:要求高导热 + 强阻燃,应对大功率、户外环境;4. LED 照明、显示模组:按需定制异形模切件,适配灯板、屏体特殊结构。  三、采购时,如何兼顾品质与效率?对于很多电子制造企业来说,采购时存在打样慢、物流周期长、售后对接不及时等问题。合肥傲琪电子作为专业导热材料厂商,主打导热硅胶片及配套热管理材料,可根据客户实际使用场景,推荐对应参数产品,并支持个性化模切、规格定制。 从前期免费试样、技术方案指导,到中期批量稳定供货,再到后期售后跟进,全程高效响应。产品经过多项权威检测,导热性能稳定、批次一致性高,完全满足量产项目的长期使用需求。 小小的一片导热材料,却是保障设备稳定运行的关键。如果您也被散热问题困扰,或是正在寻找长期合作的导热硅胶片供应商,可以多多关注合肥傲琪电子,用专业解决方案解决设备散热难题。 
设备频繁发烫?原来问题出在这
开源硬件平台
测试 测试测试测试
开源硬件平台
优质硬件创作分享平台
打赏记录
服务时间:周一至周六 9::00-18:00 · 联系地址:中国·深圳(福田区商报路奥林匹克大厦27楼) · 媒体沟通:pr@jlc.com · 集团介绍
移动社区