TypeScript WebSocket封装类详解

完整注释版代码

/**
 * WebSocket 消息接口
 * 定义WebSocket通信的消息格式
 * @template T 消息数据的类型,默认为any
 */
export interface WebSocketMessage<T = any> {
  /** 消息类型,用于区分不同的业务场景 */
  type: string;
  /** 消息数据,泛型T允许灵活定义数据结构 */
  data: T;
  /** 消息时间戳,用于记录消息创建时间 */
  timestamp: number;
}

/**
 * WebSocket 状态枚举
 * 对应WebSocket的readyState属性值
 */
export enum WebSocketStatus {
  /** 连接中 - WebSocket正在建立连接 */
  CONNECTING = 0,
  /** 打开/已连接 - 连接已建立,可以通信 */
  OPEN = 1,
  /** 关闭中/断开中 - 连接正在关闭 */
  CLOSING = 2,
  /** 已关闭/已断开 - 连接已关闭或未能建立 */
  CLOSED = 3
}

/**
 * 托管 WebSocket 配置选项接口
 * 用于配置ManagedWebSocket的行为
 */
export interface ManagedWebSocketOptions {
  /** WebSocket连接地址,如:ws://localhost:8080 */
  url: string;
  /** 可选的WebSocket子协议 */
  protocols?: string | string[];
  /** 是否自动重连,默认false */
  autoReconnect?: boolean;
  /** 重连间隔时间(毫秒),默认3000 */
  reconnectInterval?: number;
  /** 最大重连尝试次数,默认5次 */
  maxReconnectAttempts?: number;
  /** 心跳间隔时间(毫秒),不设置则不开启心跳 */
  heartbeatInterval?: number;
  /** 连接成功时的回调函数 */
  onOpen?: (event: Event) => void;
  /** 接收到消息时的回调函数 */
  onMessage?: <T>(message: WebSocketMessage<T>) => void;
  /** 发生错误时的回调函数 */
  onError?: (event: Event) => void;
  /** 连接关闭时的回调函数 */
  onClose?: (event: CloseEvent) => void;
}

/**
 * 托管 WebSocket 类
 * 具备自动重连、心跳检测等管理功能的 WebSocket 封装
 * 
 * 功能特性:
 * - 自动重连机制(支持指数退避算法)
 * - 心跳保活机制
 * - 连接状态管理
 * - 错误处理和恢复
 * - 手动重连控制
 */
export class ManagedWebSocket {
  /** WebSocket实例 */
  private ws: WebSocket | null = null;
  /** 当前重连尝试次数 */
  private reconnectAttempts = 0;
  /** 心跳定时器ID */
  private heartbeatTimer: number | null = null;
  /** 是否手动关闭的标志,手动关闭时不自动重连 */
  private isManualClose = false;

  /**
   * 构造函数
   * @param options 配置选项
   */
  constructor(private options: ManagedWebSocketOptions) {
    // 创建实例时立即建立连接
    this.connect();
  }

  /**
   * 建立WebSocket连接
   * 创建WebSocket实例并设置事件处理器
   */
  private connect(): void {
    try {
      // 创建WebSocket实例
      this.ws = new WebSocket(this.options.url, this.options.protocols);
      // 设置事件监听器
      this.setupEventHandlers();
    } catch (error) {
      console.error('WebSocket connection failed:', error);
      // 连接失败时尝试重连
      this.handleReconnect();
    }
  }

  /**
   * 设置WebSocket事件处理器
   * 处理连接打开、消息接收、错误和关闭事件
   */
  private setupEventHandlers(): void {
    if (!this.ws) return;

    // 连接成功事件
    this.ws.onopen = (event: Event) => {
      console.log('WebSocket connected');
      // 重置重连计数器
      this.reconnectAttempts = 0;
      // 启动心跳检测
      this.startHeartbeat();
      // 调用用户提供的onOpen回调
      this.options.onOpen?.(event);
    };

    // 消息接收事件
    this.ws.onmessage = (event: MessageEvent) => {
      try {
        // 解析JSON格式的消息
        const message: WebSocketMessage = JSON.parse(event.data);
        // 调用用户提供的onMessage回调
        this.options.onMessage?.(message);
        
        // 特殊处理:如果是心跳响应消息
        if (message.type === 'pong') {
          this.handlePong();
        }
      } catch (error) {
        console.error('Failed to parse WebSocket message:', error);
      }
    };

    // 错误事件
    this.ws.onerror = (event: Event) => {
      console.error('WebSocket error:', event);
      // 调用用户提供的onError回调
      this.options.onError?.(event);
    };

    // 连接关闭事件
    this.ws.onclose = (event: CloseEvent) => {
      console.log('WebSocket closed:', event.code, event.reason);
      // 停止心跳检测
      this.stopHeartbeat();
      // 调用用户提供的onClose回调
      this.options.onClose?.(event);

      // 如果不是手动关闭且启用了自动重连,则尝试重连
      if (!this.isManualClose && this.options.autoReconnect) {
        this.handleReconnect();
      }
    };
  }

  /**
   * 处理重连逻辑
   * 使用指数退避算法避免频繁重连
   */
  private handleReconnect(): void {
    // 1. 检查是否超过最大重连次数
    const maxAttempts = this.options.maxReconnectAttempts || 5;
    if (this.reconnectAttempts >= maxAttempts) {
      console.error('Max reconnection attempts reached');
      return;
    }

    // 2. 计算重连间隔(指数退避算法)
    const baseInterval = this.options.reconnectInterval || 3000;
    // 重连间隔 = 基础间隔 × 1.5^重连次数,让重连间隔越来越长
    const backoffInterval = baseInterval * Math.pow(1.5, this.reconnectAttempts);

    console.log(`Attempting to reconnect in ${backoffInterval}ms (attempt ${this.reconnectAttempts + 1})`);
    
    // 3. 设置定时器进行重连
    setTimeout(() => {
      this.reconnectAttempts++;
      this.connect();
    }, backoffInterval);
  }

  /**
   * 启动心跳检测
   * 定期发送ping消息检测连接是否存活
   */
  private startHeartbeat(): void {
    // 如果没有设置心跳间隔,则不启动心跳
    if (!this.options.heartbeatInterval) return;

    // 设置定时器,定期发送心跳
    this.heartbeatTimer = window.setInterval(() => {
      if (this.isConnected()) {
        // 发送ping消息
        this.send({ 
          type: 'ping', 
          data: null, 
          timestamp: Date.now() 
        });
      }
    }, this.options.heartbeatInterval);
  }

  /**
   * 停止心跳检测
   * 清理心跳定时器
   */
  private stopHeartbeat(): void {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
  }

  /**
   * 处理心跳响应
   * 接收到pong消息时的处理,可用于更新最后活跃时间
   */
  private handlePong(): void {
    // 这里可以记录最后收到pong的时间
    // 用于检测连接是否真的存活,如果长时间没收到pong可以主动重连
    // 当前实现为空,可根据需要扩展
  }

  /**
   * 发送消息
   * @param message 要发送的消息
   * @returns 发送是否成功
   */
  public send<T>(message: WebSocketMessage<T>): boolean {
    // 检查连接状态
    if (!this.isConnected()) {
      console.error('WebSocket is not connected');
      return false;
    }

    try {
      // 将消息对象转换为JSON字符串并发送
      this.ws!.send(JSON.stringify(message));
      return true;
    } catch (error) {
      console.error('Failed to send WebSocket message:', error);
      return false;
    }
  }

  /**
   * 主动关闭WebSocket连接
   * @param code 关闭代码,默认1000(正常关闭)
   * @param reason 关闭原因
   */
  public close(code?: number, reason?: string): void {
    // 设置手动关闭标志,避免自动重连
    this.isManualClose = true;
    // 停止心跳检测
    this.stopHeartbeat();
    
    // 关闭WebSocket连接
    if (this.ws) {
      this.ws.close(code || 1000, reason);
    }
  }

  /**
   * 检查连接是否处于打开状态
   * @returns 是否已连接
   */
  public isConnected(): boolean {
    return this.ws?.readyState === WebSocketStatus.OPEN;
  }

  /**
   * 获取当前WebSocket状态
   * @returns WebSocket状态枚举值
   */
  public getReadyState(): WebSocketStatus {
    return this.ws?.readyState ?? WebSocketStatus.CLOSED;
  }

  /**
   * 手动触发重连
   * 用于网络恢复等场景下的主动重连
   */
  public reconnect(): void {
    // 重置手动关闭标志,允许重连
    this.isManualClose = false;
    // 重置重连计数器
    this.reconnectAttempts = 0;
    
    // 如果存在现有连接,先关闭
    if (this.ws) {
      this.ws.close();
    }
    
    // 建立新连接
    this.connect();
  }
}

详细分析讲解

1. 核心设计思想

这个 ManagedWebSocket 类是对原生 WebSocket 的增强封装,主要解决了以下问题:

  • 连接稳定性:自动重连机制

  • 连接健康度:心跳检测

  • 状态管理:统一的状态枚举

  • 错误恢复:完善的错误处理

2. 核心组件分析

2.1 消息格式 (WebSocketMessage)

typescript

interface WebSocketMessage<T = any> {
  type: string;       // 消息类型标识
  data: T;           // 消息内容(泛型)
  timestamp: number; // 时间戳
}

作用:统一前后端通信的消息格式,便于类型检查和数据处理。

2.2 连接状态 (WebSocketStatus)

typescript

enum WebSocketStatus {
  CONNECTING = 0,  // 连接中
  OPEN = 1,        // 已连接
  CLOSING = 2,     // 关闭中
  CLOSED = 3       // 已关闭
}

作用:使用枚举替代魔术数字,提高代码可读性。

2.3 配置选项 (ManagedWebSocketOptions)

提供灵活的配置,包括:

  • 基础配置:URL、协议

  • 重连配置:自动重连、重连策略

  • 心跳配置:保活机制

  • 事件回调:各种状态的回调函数

3. 关键技术点

3.1 自动重连机制

typescript

private handleReconnect(): void {
  // 指数退避算法:重连间隔越来越长
  const backoffInterval = interval * Math.pow(1.5, this.reconnectAttempts);
}

原理:使用指数退避算法避免频繁重连对服务器造成压力。

3.2 心跳检测

typescript

private startHeartbeat(): void {
  this.heartbeatTimer = window.setInterval(() => {
    if (this.isConnected()) {
      this.send({ type: 'ping', data: null, timestamp: Date.now() });
    }
  }, this.options.heartbeatInterval);
}

作用:定期发送ping消息,检测连接是否真正可用。

3.3 手动关闭标识

typescript

private isManualClose = false;

作用:区分主动关闭和意外断开,只有意外断开才自动重连。

4. 使用示例

typescript

// 创建托管WebSocket实例
const ws = new ManagedWebSocket({
  url: 'ws://localhost:8080',
  autoReconnect: true,
  reconnectInterval: 3000,
  maxReconnectAttempts: 5,
  heartbeatInterval: 30000,
  
  onOpen: (event) => {
    console.log('连接成功');
  },
  
  onMessage: (message) => {
    console.log('收到消息:', message);
    
    // 根据消息类型处理不同业务
    switch (message.type) {
      case 'chat':
        console.log('聊天消息:', message.data);
        break;
      case 'notification':
        console.log('通知:', message.data);
        break;
    }
  },
  
  onClose: (event) => {
    console.log('连接关闭', event.code, event.reason);
  }
});

// 发送消息
ws.send({
  type: 'chat',
  data: { text: 'Hello World' },
  timestamp: Date.now()
});

// 检查连接状态
if (ws.isConnected()) {
  console.log('连接正常');
}

// 手动重连
ws.reconnect();

// 主动关闭
ws.close(1000, '用户主动关闭');

5. 新手学习要点

5.1 TypeScript 特性
  • 泛型WebSocketMessage<T> 让消息数据可以是任意类型

  • 接口:定义对象结构,提供类型安全

  • 枚举:替代魔术数字,提高可读性

  • 可选属性protocols?: string 中的 ? 表示该属性可选

5.2 设计模式
  • 观察者模式:通过回调函数通知状态变化

  • 策略模式:配置选项允许自定义行为

  • 状态模式:通过状态枚举管理连接生命周期

5.3 错误处理

typescript

try {
  // 可能出错的代码
} catch (error) {
  // 错误处理
  console.error('操作失败:', error);
  // 恢复措施
  this.handleReconnect();
}

6. 扩展建议

可以根据需要添加以下功能:

  1. 消息队列:连接断开时缓存未发送的消息

  2. 连接超时:设置连接建立超时时间

  3. 认证重连:支持带认证信息的重连

  4. 网络状态检测:结合navigator.onLine检测网络状态

这个封装类很好地展示了如何将一个基础API封装成生产可用的工具类,是学习TypeScript和网络编程的优秀示例!


结合这个 WebSocket 实例,我来为你详细讲解 class 和 interface 的区别和作用。

1. 基本概念对比

interface(接口)

typescript

// 接口:定义"应该有什么"
export interface WebSocketMessage<T = any> {
  type: string;      // 必须有 type
  data: T;          // 必须有 data
  timestamp: number; // 必须有 timestamp
}

class(类)

typescript

// 类:定义"是什么" + "能做什么"
export class ManagedWebSocket {
  private ws: WebSocket | null = null; // 属性
  private reconnectAttempts = 0;       // 属性
  
  constructor(private options: ManagedWebSocketOptions) { // 构造函数
    this.connect();
  }
  
  public send<T>(message: WebSocketMessage<T>): boolean { // 方法
    // 具体实现...
  }
}

2. 在实例中的具体作用分析

2.1 interface 的作用

定义数据结构(WebSocketMessage)

typescript

export interface WebSocketMessage<T = any> {
  type: string;
  data: T;
  timestamp: number;
}

// 使用示例:类型约束
const chatMessage: WebSocketMessage<{ text: string }> = {
  type: 'chat',
  data: { text: 'Hello' },  // 这里必须是 { text: string } 类型
  timestamp: Date.now()
};

const notificationMessage: WebSocketMessage<{ title: string }> = {
  type: 'notification',
  data: { title: 'Alert' }, // 这里必须是 { title: string } 类型
  timestamp: Date.now()
};

作用:确保所有 WebSocket 消息都有统一的结构,便于序列化和解析。

定义配置契约(ManagedWebSocketOptions)

typescript

export interface ManagedWebSocketOptions {
  url: string;  // 必须的配置
  protocols?: string | string[];  // 可选的配置
  autoReconnect?: boolean;
  // ... 其他配置
}

作用:明确告诉使用者创建 ManagedWebSocket 时需要提供哪些配置。

定义回调函数签名

typescript

onMessage?: <T>(message: WebSocketMessage<T>) => void;

作用:规定回调函数的参数类型,确保类型安全。

2.2 class 的作用

封装实现逻辑

typescript

export class ManagedWebSocket {
  private ws: WebSocket | null = null;        // 封装内部状态
  private reconnectAttempts = 0;              // 封装内部状态
  private heartbeatTimer: number | null = null; // 封装内部状态
  
  // 封装连接逻辑
  private connect(): void {
    this.ws = new WebSocket(this.options.url, this.options.protocols);
    this.setupEventHandlers();
  }
  
  // 封装重连逻辑
  private handleReconnect(): void {
    // 复杂的重连算法实现...
  }
}
提供公共 API

typescript

public send<T>(message: WebSocketMessage<T>): boolean {
  // 对外提供发送消息的能力
}

public close(code?: number, reason?: string): void {
  // 对外提供关闭连接的能力
}

public isConnected(): boolean {
  // 对外提供状态查询能力
}
管理对象生命周期

typescript

constructor(private options: ManagedWebSocketOptions) {
  this.connect();  // 创建时自动连接
}

public close(code?: number, reason?: string): void {
  this.isManualClose = true;
  this.stopHeartbeat();
  if (this.ws) {
    this.ws.close(code || 1000, reason);
  }
}

3. 核心区别详解

3.1 编译结果不同

interface - 编译后消失

typescript

// TypeScript 源码
interface WebSocketMessage {
  type: string;
  data: any;
}

// 编译后的 JavaScript:什么都没有!
// interface 只在编译阶段用于类型检查
class - 编译后保留

typescript

// TypeScript 源码
class ManagedWebSocket {
  private ws = null;
  connect() { /* ... */ }
}

// 编译后的 JavaScript
class ManagedWebSocket {
  constructor() {
    this.ws = null;
  }
  connect() { /* ... */ }
}

3.2 实例化能力不同

interface - 不能实例化

typescript

const message = new WebSocketMessage(); // ❌ 错误!接口不能new
class - 可以实例化

typescript

const ws = new ManagedWebSocket({ url: 'ws://...' }); // ✅ 正确!

3.3 实现与声明的关系

interface 声明"有什么"

typescript

// 声明:一个可以连接的东西应该有 connect 方法
interface Connectable {
  connect(): void;
  isConnected(): boolean;
}
class 实现"怎么做"

typescript

// 实现:具体怎么连接
class ManagedWebSocket implements Connectable {
  connect(): void {
    // 具体的连接实现
    this.ws = new WebSocket(this.options.url);
  }
  
  isConnected(): boolean {
    // 具体的状态检查实现
    return this.ws?.readyState === WebSocketStatus.OPEN;
  }
}

4. 实际配合使用场景

4.1 类实现接口(契约编程)

typescript

// 定义契约
interface Reconnectable {
  reconnect(): void;
  maxReconnectAttempts: number;
}

// 类实现契约
export class ManagedWebSocket implements Reconnectable {
  public maxReconnectAttempts: number;
  
  public reconnect(): void {
    this.isManualClose = false;
    this.reconnectAttempts = 0;
    if (this.ws) {
      this.ws.close();
    }
    this.connect();
  }
}

4.2 接口描述类实例的形状

typescript

// 接口描述类实例应该有的公共方法
export interface IManagedWebSocket {
  send<T>(message: WebSocketMessage<T>): boolean;
  close(code?: number, reason?: string): void;
  isConnected(): boolean;
  reconnect(): void;
}

// 类实现这个接口
export class ManagedWebSocket implements IManagedWebSocket {
  // 必须实现接口中定义的所有方法
  public send<T>(message: WebSocketMessage<T>): boolean {
    // 实现...
  }
  
  public close(code?: number, reason?: string): void {
    // 实现...
  }
  
  // ... 其他方法
}

4.3 依赖注入中的使用

typescript

// 定义服务接口
interface WebSocketService {
  sendMessage<T>(type: string, data: T): boolean;
  onMessage<T>(callback: (message: WebSocketMessage<T>) => void): void;
}

// 实现服务
class ManagedWebSocketService implements WebSocketService {
  private ws: ManagedWebSocket;
  
  constructor(options: ManagedWebSocketOptions) {
    this.ws = new ManagedWebSocket(options);
  }
  
  sendMessage<T>(type: string, data: T): boolean {
    return this.ws.send({
      type,
      data,
      timestamp: Date.now()
    });
  }
  
  onMessage<T>(callback: (message: WebSocketMessage<T>) => void): void {
    this.ws.options.onMessage = callback;
  }
}

5. 新手使用建议

什么时候用 interface?

  1. 定义数据模型:如 API 响应、消息格式

  2. 函数参数约束:确保传入的对象有特定属性

  3. 类公共 API 描述:定义类应该实现的方法

  4. 配置对象定义:如构造函数的配置选项

什么时候用 class?

  1. 需要实例化对象:要创建多个相似对象

  2. 封装复杂逻辑:有内部状态和复杂方法

  3. 需要继承:要扩展或重写现有功能

  4. 管理生命周期:如连接、资源清理等

实际开发中的模式

typescript

// 1. 先用 interface 设计
interface User {
  id: number;
  name: string;
  email: string;
}

interface UserService {
  getUser(id: number): Promise<User>;
  updateUser(user: User): Promise<boolean>;
}

// 2. 再用 class 实现
class HttpUserService implements UserService {
  private baseUrl: string;
  
  constructor(baseUrl: string) {
    this.baseUrl = baseUrl;
  }
  
  async getUser(id: number): Promise<User> {
    const response = await fetch(`${this.baseUrl}/users/${id}`);
    return response.json();
  }
  
  async updateUser(user: User): Promise<boolean> {
    // 实现更新逻辑
    return true;
  }
}

6. 总结

特性interfaceclass
作用定义结构契约创建具体实现
实例化❌ 不能✅ 能
编译后消失保留
包含实现❌ 不能✅ 能
访问修饰符❌ 没有✅ 有
继承接口继承接口类继承类

简单记忆

  • interface = 蓝图/合同(规定应该有什么)

  • class = 房子/实现(具体建造和使用)

在这个 WebSocket 例子中:

  • interface 用来定义消息格式和配置选项(数据层面)

  • class 用来实现具体的连接管理逻辑(行为层面)

两者配合使用,既能保证类型安全,又能提供完整的业务功能实现。


封闭好的类需要导出才能在组件中调用。让我详细解释这个机制。

1. 模块系统基础

1.1 导出(Export)

typescript

// managed-websocket.ts
export class ManagedWebSocket {  // 使用 export 关键字
  // ... 类实现
}

export interface WebSocketMessage {
  // ... 接口定义
}

export enum WebSocketStatus {
  // ... 枚举定义
}

1.2 导入(Import)

typescript

// 组件文件 component.ts
import { 
  ManagedWebSocket, 
  WebSocketMessage, 
  WebSocketStatus 
} from './managed-websocket';  // 从文件路径导入

2. 为什么需要导出?

2.1 模块隔离

现代前端开发中,每个文件都是一个独立的模块:

typescript

// file-a.ts
class MyClass { }  // 没有 export,只在当前文件可见

// file-b.ts  
import { MyClass } from './file-a';  // ❌ 错误!MyClass 不可见

2.2 作用域保护

typescript

// utils.ts
// 内部使用的辅助函数,不需要导出
function formatDate(date: Date): string {
  return date.toISOString();
}

// 对外提供的工具函数,需要导出
export function generateId(): string {
  return Math.random().toString(36).substr(2, 9);
}

3. 不同的导出方式

3.1 命名导出(Named Exports)

typescript

// 方式1:直接导出
export class ManagedWebSocket { }

// 方式2:先定义后导出
class ManagedWebSocket { }
interface WebSocketMessage { }
enum WebSocketStatus { }

export { ManagedWebSocket, WebSocketMessage, WebSocketStatus };

// 方式3:重命名导出
export { ManagedWebSocket as WSManager };

3.2 默认导出(Default Export)

typescript

// 一个文件通常只有一个默认导出
export default class ManagedWebSocket {
  // ...
}

// 或者
class ManagedWebSocket { }
export default ManagedWebSocket;

3.3 混合导出

typescript

export class ManagedWebSocket {
  // 主要功能类
}

export interface WebSocketMessage {
  // 辅助类型
}

// 工具函数作为默认导出
export default function createWebSocket(options: any) {
  return new ManagedWebSocket(options);
}

4. 对应的导入方式

4.1 命名导入

typescript

import { ManagedWebSocket, WebSocketMessage } from './managed-websocket';

// 重命名导入
import { ManagedWebSocket as WS } from './managed-websocket';

4.2 默认导入

typescript

import ManagedWebSocket from './managed-websocket';
// 或者重命名
import WS from './managed-websocket';

4.3 全部导入

typescript

import * as WebSocketModule from './managed-websocket';

// 使用
const ws = new WebSocketModule.ManagedWebSocket(options);

5. 在实际项目中的使用

5.1 React 组件中的使用

typescript

// components/ChatComponent.tsx
import React, { useState, useEffect } from 'react';
import { ManagedWebSocket, WebSocketMessage } from '../utils/managed-websocket';

const ChatComponent: React.FC = () => {
  const [websocket, setWebsocket] = useState<ManagedWebSocket | null>(null);
  const [messages, setMessages] = useState<string[]>([]);

  useEffect(() => {
    // 创建 WebSocket 实例
    const ws = new ManagedWebSocket({
      url: 'ws://localhost:8080/chat',
      autoReconnect: true,
      onMessage: (message: WebSocketMessage) => {
        setMessages(prev => [...prev, message.data]);
      }
    });

    setWebsocket(ws);

    // 清理函数
    return () => {
      ws.close();
    };
  }, []);

  const sendMessage = (text: string) => {
    if (websocket?.isConnected()) {
      websocket.send({
        type: 'chat',
        data: text,
        timestamp: Date.now()
      });
    }
  };

  return (
    <div>
      {/* 组件 JSX */}
    </div>
  );
};

export default ChatComponent;  // 导出组件供其他文件使用

5.2 Vue 组件中的使用

typescript

<!-- components/ChatComponent.vue -->
<template>
  <div>
    <!-- 模板内容 -->
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
import { ManagedWebSocket, WebSocketMessage } from '../utils/managed-websocket';

export default defineComponent({
  name: 'ChatComponent',
  setup() {
    const websocket = ref<ManagedWebSocket | null>(null);
    const messages = ref<string[]>([]);

    onMounted(() => {
      websocket.value = new ManagedWebSocket({
        url: 'ws://localhost:8080/chat',
        autoReconnect: true,
        onMessage: (message: WebSocketMessage) => {
          messages.value.push(message.data);
        }
      });
    });

    onUnmounted(() => {
      websocket.value?.close();
    });

    const sendMessage = (text: string) => {
      if (websocket.value?.isConnected()) {
        websocket.value.send({
          type: 'chat',
          data: text,
          timestamp: Date.now()
        });
      }
    };

    return {
      messages,
      sendMessage
    };
  }
});
</script>

5.3 Angular 服务中的使用

typescript

// services/websocket.service.ts
import { Injectable } from '@angular/core';
import { ManagedWebSocket, WebSocketMessage } from '../utils/managed-websocket';

@Injectable({
  providedIn: 'root'  // Angular 的导出方式
})
export class WebSocketService {
  private websocket: ManagedWebSocket | null = null;

  connect(url: string): void {
    this.websocket = new ManagedWebSocket({
      url,
      autoReconnect: true,
      onMessage: (message: WebSocketMessage) => {
        this.handleMessage(message);
      }
    });
  }

  private handleMessage(message: WebSocketMessage): void {
    // 处理消息
  }

  sendMessage(data: any): boolean {
    return this.websocket?.send({
      type: 'message',
      data,
      timestamp: Date.now()
    }) ?? false;
  }

  disconnect(): void {
    this.websocket?.close();
  }
}

6. 导出最佳实践

6.1 按功能模块组织

typescript

// websocket/index.ts - 入口文件
export { ManagedWebSocket } from './managed-websocket';
export { WebSocketMessage } from './types';
export { WebSocketStatus } from './enums';
export { createWebSocket, closeAllConnections } from './utils';

// 使用时可以一次性导入
import { ManagedWebSocket, WebSocketMessage } from './websocket';

6.2 控制导出范围

typescript

// managed-websocket.ts
export class ManagedWebSocket {  // 公共 API
  public send() { }     // 公共方法
  public close() { }    // 公共方法
  private connect() { } // 私有方法,不需要导出
}

// 只导出用户需要使用的部分
export { ManagedWebSocket };
// 不导出内部使用的辅助函数和类

6.3 使用 Barrel Export

typescript

// utils/index.ts
export * from './websocket';
export * from './validation';
export * from './formatters';

// 组件中导入
import { ManagedWebSocket, validateEmail } from '../utils';

7. 常见错误和解决方案

7.1 忘记导出

typescript

// ❌ 错误:类没有导出
class ManagedWebSocket { }

// ✅ 正确:使用 export
export class ManagedWebSocket { }

7.2 导出名称不匹配

typescript

// 导出时
export { ManagedWebSocket as WSManager };

// 导入时
import { ManagedWebSocket } from './file';  // ❌ 错误
import { WSManager } from './file';         // ✅ 正确

7.3 循环依赖

typescript

// file-a.ts
import { something } from './file-b';
export class ClassA { }

// file-b.ts  
import { ClassA } from './file-a';  // ❌ 循环依赖

8. 总结

关键点:

  1. 必须导出:类、接口、函数等需要跨文件使用时必须使用 export

  2. 模块作用域:每个文件都是独立模块,默认情况下外部无法访问

  3. 按需导出:只导出需要公开的 API,保持内部实现私有

  4. 一致性:保持导出/导入风格一致

简单记忆:

  • 想在其他文件使用 → 加 export

  • 想在当前文件使用其他文件的代码 → 加 import

  • 保持接口最小化 → 只导出必要的部分

这就是现代 JavaScript/TypeScript 模块系统的工作原理!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值