You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在类方法中同时访问WebSocket实例与类自身实例?

WebSocket流管理类:同时访问类实例与WebSocket实例的简洁方案

问题背景

现有一个管理多WebSocket连接的Stream类,需要在open、close等事件回调中同时访问Stream类实例(获取params、ws数组等)和触发事件的WebSocket实例(调用send、定位连接等)。

原始类代码如下:

class Stream implements IStream {
  private ws: WebSocket[] = []
  private params: string[] = []
  private streamCount: number = 2
  private url: string; // 补充缺失的属性定义

  constructor(url: string, params: string[]) {
    this.url = url
    this.params = params
  }

  private _onOpen() {
    // 需求:this → WebSocket实例,同时拿到Stream实例的params
    this.send(
      JSON.stringify({
        params: that.params
      })
    )
  }

  private _onMessage(msg: Buffer) {
    const jsonObj = JSON.parse(msg.toString())
    console.log(jsonObj)
  }

  private _onClose(msg) {
    console.error(msg)
    // 需求:this → WebSocket实例,同时拿到Stream实例的ws数组和url
    const idx = that.ws.indexOf(this)
    that.ws[idx] = new WebSocket(that.url)
  }

  private _setWsListener(ws: WebSocket) {
    ws.on('error', console.error)
    ws.on('open', this._onOpen)
    ws.on('message', this._onMessage)
    ws.on('close', this._onClose)
  }

  public listen() {
    for (let i = 0; i < this.streamCount; i++) {
      const conn = new WebSocket(this.url)
      this._setWsListener(conn)
      this.ws.push(conn)
    }
  }
}

尝试过两种方案但都有弊端:

  • 使用bind(this)绑定类实例,但无法访问WebSocket实例;
  • 让回调函数返回匿名函数,虽能解决问题但代码冗余复杂。

简洁解决方案

方案1:箭头函数包裹+直接传参

利用箭头函数的词法作用域特性(箭头函数内的this指向外层的Stream实例),在绑定事件时直接将WebSocket实例作为参数传入回调:

class Stream implements IStream {
  private ws: WebSocket[] = []
  private params: string[] = []
  private streamCount: number = 2
  private url: string;

  constructor(url: string, params: string[]) {
    this.url = url
    this.params = params
  }

  private _onOpen(ws: WebSocket) {
    // this → Stream实例,ws → WebSocket实例
    ws.send(
      JSON.stringify({
        params: this.params
      })
    )
  }

  private _onMessage(msg: Buffer) {
    const jsonObj = JSON.parse(msg.toString())
    console.log(jsonObj)
  }

  private _onClose(msg: any, ws: WebSocket) {
    console.error(msg)
    // this → Stream实例,ws → WebSocket实例
    const idx = this.ws.indexOf(ws)
    if (idx !== -1) {
      this.ws[idx] = new WebSocket(this.url)
      this._setWsListener(this.ws[idx])
    }
  }

  private _setWsListener(ws: WebSocket) {
    ws.on('error', console.error)
    // 用箭头函数包裹,同时传入ws实例
    ws.on('open', () => this._onOpen(ws))
    ws.on('message', (msg) => this._onMessage(msg))
    ws.on('close', (msg) => this._onClose(msg, ws))
  }

  public listen() {
    for (let i = 0; i < this.streamCount; i++) {
      const conn = new WebSocket(this.url)
      this._setWsListener(conn)
      this.ws.push(conn)
    }
  }
}

方案2:bind绑定类实例+预置参数

通过bind同时绑定Stream实例为回调的this,并将WebSocket实例作为预置参数传入回调:

class Stream implements IStream {
  private ws: WebSocket[] = []
  private params: string[] = []
  private streamCount: number = 2
  private url: string;

  constructor(url: string, params: string[]) {
    this.url = url
    this.params = params
  }

  private _onOpen(ws: WebSocket) {
    // this → Stream实例,ws → WebSocket实例
    ws.send(
      JSON.stringify({
        params: this.params
      })
    )
  }

  private _onMessage(msg: Buffer) {
    const jsonObj = JSON.parse(msg.toString())
    console.log(jsonObj)
  }

  private _onClose(ws: WebSocket, msg: any) {
    console.error(msg)
    // this → Stream实例,ws → WebSocket实例
    const idx = this.ws.indexOf(ws)
    if (idx !== -1) {
      this.ws[idx] = new WebSocket(this.url)
      this._setWsListener(this.ws[idx])
    }
  }

  private _setWsListener(ws: WebSocket) {
    ws.on('error', console.error)
    // bind绑定this为Stream实例,同时预置ws为第一个参数
    ws.on('open', this._onOpen.bind(this, ws))
    ws.on('message', this._onMessage.bind(this))
    ws.on('close', this._onClose.bind(this, ws))
  }

  public listen() {
    for (let i = 0; i < this.streamCount; i++) {
      const conn = new WebSocket(this.url)
      this._setWsListener(conn)
      this.ws.push(conn)
    }
  }
}

方案说明

两种方案都无需额外嵌套函数,代码简洁直观:

  • 箭头函数方案更符合现代TS写法,可读性强;
  • bind方案适合习惯传统函数绑定写法的场景。

同时补充了原始类中缺失的url属性定义,避免运行时错误。

内容的提问来源于stack exchange,提问作者user3077593

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 19:37:25