WebSocket观察者模式在前端的实现与优化

1. 项目背景与核心价值

作为一个从C++转向前端开发的工程师,我深刻理解后端开发者在前端领域可能遇到的思维转换障碍。这个系列文章记录了我从零开始构建实时通信系统的完整过程,本篇重点探讨如何用观察者模式实现WebSocket订阅机制。

对于习惯C++面向对象思维的开发者来说,观察者模式是个非常熟悉的伙伴。但在前端领域实现它时,我们需要考虑浏览器环境的特殊性:单线程事件循环、异步回调机制、以及WebSocket连接的生命周期管理。这个实现方案完美融合了后端的设计模式与前端的运行环境特点。

需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。

2. 观察者模式在前端的特殊实现

2.1 经典模式与前端适配

传统观察者模式通常包含三个核心组件:

  • Subject(主题):维护观察者列表,提供注册/注销接口
  • Observer(观察者):定义通知接口
  • ConcreteObserver(具体观察者):实现具体响应逻辑

在前端实现时,我们需要做以下关键调整:

typescript复制interface WebSocketObserver {
  update(data: any): void;
  eventType: string;  // 新增字段,用于区分不同事件类型
}

class WebSocketSubject {
  private observers: Map<string, WebSocketObserver[]> = new Map();
  
  // 注册时需指定关注的事件类型
  attach(eventType: string, observer: WebSocketObserver) {
    if (!this.observers.has(eventType)) {
      this.observers.set(eventType, []);
    }
    this.observers.get(eventType)?.push(observer);
  }
}

关键调整:传统观察者模式通常不区分事件类型,但在WebSocket场景下,我们需要支持多种消息类型的订阅,因此引入了事件类型区分机制。

2.2 连接状态管理

WebSocket连接有其特有的生命周期状态,我们需要扩展观察者模式来应对:

typescript复制enum ConnectionState {
  CONNECTING,
  OPEN,
  CLOSING,
  CLOSED,
  RECONNECTING
}

class WebSocketSubject {
  private state: ConnectionState = ConnectionState.CLOSED;
  private reconnectAttempts = 0;
  private maxReconnectAttempts = 5;
  
  // 状态变更时通知所有观察者
  private notifyStateChange() {
    Array.from(this.observers.values())
      .flat()
      .forEach(observer => {
        if (typeof observer.onStateChange === 'function') {
          observer.onStateChange(this.state);
        }
      });
  }
}

3. 完整实现方案

3.1 WebSocket封装核心

typescript复制class WebSocketManager implements WebSocketSubject {
  private socket: WebSocket | null = null;
  private url: string;
  private protocols?: string | string[];
  
  constructor(url: string, protocols?: string | string[]) {
    this.url = url;
    this.protocols = protocols;
    this.connect();
  }
  
  private connect() {
    this.socket = new WebSocket(this.url, this.protocols);
    this.setState(ConnectionState.CONNECTING);
    
    this.socket.onopen = () => {
      this.setState(ConnectionState.OPEN);
      this.reconnectAttempts = 0;
    };
    
    this.socket.onmessage = (event) => {
      try {
        const data = JSON.parse(event.data);
        this.notify(data.type, data.payload);
      } catch (e) {
        console.error('Failed to parse WebSocket message', e);
      }

内容推荐

已经到底了哦
已经到底了哦