Q19 · Web3 场景优化

交易所前端需要频繁更新价格/盘口,你会如何设计推送/订阅机制以兼顾性能?

WebSocket实时数据节流渲染

⚡ 速记答案(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) {
    // 增量更新订单簿
    // ...
  }
}
💡
面试技巧:回答性能问题时,先说指标和标准,再讲优化手段,最后结合实际项目经验。