闭包不封装 websocket 实例,而是封装更新逻辑所需的私有上下文,如节流函数、缓存、状态等,实现防抖、节流、缓存、多模块隔离及热更新版本共存。

闭包本身不直接“封装 WebSocket 更新逻辑”,但它能帮你安全地隔离和管理高频更新的副作用——比如防抖、节流、缓存、状态暂存等。关键不是把 WebSocket 实例塞进闭包,而是用闭包捕获并维护更新行为所需的私有上下文,避免与组件生命周期或多次渲染冲突。
用闭包封装节流/防抖函数,而非 WebSocket 实例
WebSocket 的 onmessage 回调本身不能加防抖或节流(会丢消息),但你收到数据后要做的 DOM 更新、状态计算、API 调用等操作,完全可以由闭包封装的节流函数来承接:
- 每次创建节流函数时,它内部闭包会记住定时器 ID、上一次执行时间、待合并的数据等,互不干扰
- 不同股票、不同协作用户、不同模块可各自拥有独立的节流实例,避免互相覆盖
- 示例:处理拖拽坐标同步
el.style.left = x + 'px';
el.style.top = y + 'px';
}, 60); // 每帧最多执行一次
ws.onmessage = (e) => {
const data = JSON.parse(e.data);
if (data.type === 'drag') {
updatePosition(data.x, data.y); // 调用闭包封装的节流函数
}
};
用闭包缓存最新值,避免重复计算或无效更新
高频行情场景下,每秒几十条消息,但 UI 不需要每条都响应。闭包可用来维护一个轻量级内存缓存(如 Map 或 plain object),只在值真正变化时才触发后续逻辑:
使用 @ainative/react-sdk 为 React 应用添加 AI 聊天和积分。适用于 (1) 安装 @ainative/react-sdk,(2) 使用 useChat hook 实现聊天完成。
- 缓存对象定义在函数作用域内,不会被外部污染
- 配合
requestAnimationFrame批量读取缓存,错峰更新 DOM - 组件卸载时,闭包自然失活,无需手动清理(前提是没泄漏到全局)
const cache = new Map();
return {
set: (symbol, price) => cache.set(symbol, price),
get: (symbol) => cache.get(symbol),
flush: () => {
cache.forEach((price, symbol) => {
document.getElementById(`price-${symbol}`).textContent = price;
});
cache.clear();
}
};
};
const cache = createPriceCache();
ws.onmessage = (e) => {
const data = JSON.parse(e.data);
cache.set(data.symbol, data.price);
requestAnimationFrame(() => cache.flush());
};
闭包配合 useRef,隔离连接状态与更新逻辑
WebSocket 实例必须用 useRef 存,但它的事件回调里要调用的更新函数,可以用闭包封装——这样既能复用同一个 ws 实例,又能为不同业务逻辑提供独立上下文:
- 比如一个页面同时展示行情 + 订单状态 + 协作光标,三套更新逻辑彼此独立
- 每个逻辑模块自建闭包,管理自己的缓存、节流器、上次更新时间
- 所有发送操作仍走
wsRef.current?.send(),但发送前的数据准备完全隔离
热更新场景下,闭包支持多版本共存
如果 WebSocket 更新逻辑需热替换(如动态加载新策略),闭包是天然的版本隔离单元:
- 每次热更生成新函数,返回新闭包,旧闭包仍在运行直到任务完成
- 旧闭包持有自己的定时器、缓存、节流状态;新闭包从头开始,互不影响
- dispose 阶段主动清空旧闭包中的资源(如 clearInterval、取消 requestAnimationFrame)










