仪表盘应优先使用 WebSocket 实现实时刷新,避免整页重载;若不可用,则用 fetch 配合完成后再定时的策略;Canvas 渲染需优化静态内容、指针绘制和数据量,按实际频率控制刷新节奏。

直接用 <meta http-equiv="refresh"> 或 setInterval(() => location.reload(), ...) 刷新整页,不是仪表盘该有的自动刷新——它会清空 canvas 状态、丢失滚动位置、打断用户交互,还可能让 WebSocket 连接反复重连。
WebSocket 是实时仪表盘数据刷新的首选方式
只要服务端支持,就该优先走 WebSocket。它建立长连接后,数据来了才更新,不轮询、不刷屏、不丢状态。
- 连接成功后监听
message事件,收到 JSON 就解析:比如{"type":"temp_update","value":23.6} - 不要在
onmessage里直接操作 DOM 或重绘 canvas;把新值存进一个共享对象(如state.temp = data.value),再交给requestAnimationFrame统一渲染 - 必须监听
error和close,并实现指数退避重连(例如首次等 1s,失败则 2s、4s、8s… 最多试 5 次) - 连接断开时 UI 要显式标记为 offline,避免用户误以为数据“卡住”了
fetch + setInterval 适合无 WebSocket 权限的轻量场景
比如树莓派本地页面调用 CGI 或 Python 脚本返回温度 HTML 片段,这种方案可行,但要注意节奏和容错。
- 别用
setInterval(() => fetch(...).then(render), 3000)这种裸写法:如果某次请求耗时 2s,下一次又立刻发起,容易堆积请求或覆盖渲染 - 改用“请求完成后再设下一次”:在
fetch().then(...).finally(() => setTimeout(doFetch, 3000)) - CGI 返回内容若只是纯数字(如
<h1>24.1</h1>),用response.text()解析比response.json()更轻量,也更容错 - 如果脚本偶尔超时或返回空,UI 上应保留上一次有效值(hold-last),而不是清零或显示 NaN
Canvas 仪表盘刷新最容易被忽略的性能陷阱
canvas 不像 DOM 有浏览器优化,每次 clearRect + 全量重绘都是 CPU 开销。实时刷新时稍不注意就会掉帧。
立即学习“前端免费学习笔记(深入)”;
- 静态部分(表盘底图、刻度线)务必预先画到离屏
<canvas></canvas>,每帧只ctx.drawImage(offlineCanvas, 0, 0) - 指针转动别用
rotate()反复变换坐标系;用三角函数算终点坐标,moveTo()→lineTo()画线更稳 - 折线图只维护最近 N 个点(如 200 个),新数据
push()后shift(),避免数组无限增长 - 不要在 render 函数里做
JSON.parse、new Date()或字符串拼接——这些应在数据到达时就做完
真正难的不是“怎么刷”,而是“刷多少”和“什么时候刷”。3 秒是常见经验值,但若数据变化频率低(如温室温度每分钟才变一次),刷太勤只是白耗资源;若指标要求亚秒级响应(如电机转速),就得关掉所有非必要绘制,甚至启用 Path2D 缓存路径。这些细节,往往比选哪种刷新机制更影响最终体验。



















