节流适用于心跳或位置坐标等“最新值优先”场景:固定时间窗口内只发一次,如1000ms节流下每200ms触发仅第1、2、3次(0/1000/2000ms)发送,中间跳过;需用闭包或类属性保存上次时间,判断当前时间-上次时间≥间隔才发送并更新,且必须校验readyState。

WebSocket 客户端发送高频心跳或位置坐标时,直接无节制发送会浪费带宽、增加服务端压力,甚至触发限流或断连。节流(throttle)能确保单位时间内最多发送一次,适合这类“最新值优先、中间值可丢弃”的场景。
节流的核心逻辑:只允许首次触发立即执行,后续触发在冷却期内被忽略
与防抖(debounce)不同,节流不等待“停止触发”,而是固定时间窗口内只放行一次。例如:设 1000ms 节流,用户每 200ms 发一次坐标,实际只发第 1 次(0ms)、第 2 次(1000ms)、第 3 次(2000ms)……中间的全部跳过。
关键点:
- 必须用闭包或类属性保存上次执行时间(不能每次调用都重置)
- 判断逻辑是:当前时间 - 上次执行时间 ≥ 间隔,才发送并更新“上次时间”
- 不依赖定时器轮询,纯函数式判断,轻量且精准
WebSocket 心跳节流实现(推荐用 class 封装)
把节流逻辑和 ws 实例绑定,避免全局变量污染,也方便复用:
立即学习“Java免费学习笔记(深入)”;
class ThrottledWebSocket {
constructor(url) {
this.ws = new WebSocket(url);
this.lastSendTime = 0;
this.throttleDelay = 5000; // 心跳间隔 5s
}
<p>sendHeartbeat() {
const now = Date.now();
if (now - this.lastSendTime >= this.throttleDelay) {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({ type: 'heartbeat', ts: now }));
this.lastSendTime = now;
}
}
}</p><p>// 可配合 setInterval 使用,但不强制——也可由业务主动调用
startHeartbeat() {
setInterval(() => this.sendHeartbeat(), 1000); // 每秒检查一次是否该发
}
}说明:
- 每秒检查一次,但真正发送只在满足间隔时发生,既省资源又保精度
- 检查
readyState防止连接未就绪时报错 - 心跳消息体建议带时间戳,便于服务端校验延迟
位置坐标节流(带“最新值捕获”优化)
单纯节流可能丢失最后一次移动信息(比如用户刚停下就断网)。更优做法是:节流 + 缓存最新坐标,到下次节流窗口开启时发缓存值(即“发最近一次变化”):
class ThrottledLocationSender {
constructor(ws, throttleDelay = 1000) {
this.ws = ws;
this.throttleDelay = throttleDelay;
this.lastSendTime = 0;
this.pendingLocation = null; // 缓存最新坐标
}
<p>updateLocation(lat, lng, accuracy = 10) {
this.pendingLocation = { lat, lng, accuracy, ts: Date.now() };
}</p><p>sendLocation() {
const now = Date.now();
if (now - this.lastSendTime >= this.throttleDelay && this.pendingLocation) {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({
type: 'location',
data: this.pendingLocation
}));
this.lastSendTime = now;
this.pendingLocation = null; // 清空缓存
}
}
}</p><p>// 外部可每 200ms 调用一次 updateLocation,每 1000ms 调用一次 sendLocation
}优势:
- 业务层自由调用
updateLocation(如监听watchPosition),无需关心频率 -
sendLocation控制实际发送节奏,且保证发出的是“最后有效值” - 断网恢复后,只要缓存未清空,下一次节流窗口仍会补发
注意事项与避坑点
节流不是万能药,需结合 WebSocket 特性注意:
-
不要在 onmessage 回调里节流发送:容易造成发送阻塞,应始终异步触发(如用
setTimeout(0)或queueMicrotask) - 节流间隔不宜小于 1s:太短失去节流意义;心跳建议 5–30s,位置建议 500ms–5s(依精度要求)
- 服务端也要做校验:仅客户端节流不可靠,服务端需检查消息时间戳或频次,防止恶意绕过
- 关闭前记得清空 pending:避免页面卸载后内存泄漏或误发旧数据


















