Q19 · Web3 场景优化
交易所前端需要频繁更新价格/盘口,你会如何设计推送/订阅机制以兼顾性能?
⚡ 速记答案(30 秒)
- 尽量使用 WebSocket / SSE / 链事件订阅,避免高频轮询
- 在前端做节流渲染:例如每 200ms 刷一次 UI,就算 50ms 来一条数据也先聚合起来
- 对数据结构做增量更新,而不是每次重建整个订单簿
- 多 tab / 多组件共享同一个数据源,避免每处都独立开一个连接
📖 详细讲解
实时数据架构
WebSocket 连接 → 数据缓冲层 → 节流渲染 → UI 更新优化策略
1. 数据层
• 单一 WebSocket 连接
• 消息队列缓冲
• 增量数据合并
2. 渲染层
• 节流更新(throttle)
• 批量 DOM 更新
• 虚拟列表
3. 状态管理
• 共享数据源
• 选择性订阅
• 数据范式化
具体实现
| 策略 | 说明 |
|---|---|
| 消息聚合 | 50ms 内的多条消息合并处理 |
| 渲染节流 | 控制 UI 更新频率(如 60fps) |
| 差量更新 | 只更新变化的部分 |
| 离屏跳过 | Tab 不可见时暂停渲染 |
💻 代码示例
节流渲染订单簿
class OrderBookManager {
private buffer: OrderUpdate[] = [];
private renderTimer: number | null = null;
private orderBook = { bids: [], asks: [] };
constructor(private onUpdate: (book: OrderBook) => void) {
this.connectWebSocket();
}
private connectWebSocket() {
const ws = new WebSocket('wss://...');
ws.onmessage = (event) => {
const update = JSON.parse(event.data);
this.buffer.push(update);
this.scheduleRender();
};
}
private scheduleRender() {
if (this.renderTimer) return;
this.renderTimer = window.setTimeout(() => {
this.flushBuffer();
this.renderTimer = null;
}, 200); // 每 200ms 最多渲染一次
}
private flushBuffer() {
// 批量应用所有更新
for (const update of this.buffer) {
this.applyUpdate(update);
}
this.buffer = [];
// 通知 UI 更新
this.onUpdate({ ...this.orderBook });
}
private applyUpdate(update: OrderUpdate) {
// 增量更新订单簿
// ...
}
}面试技巧:回答性能问题时,先说指标和标准,再讲优化手段,最后结合实际项目经验。