首页 > 网页制作 >如何利用“单例模式”配合闭包确保在单页应用中全局仅存在一个 WebSocket 长连接实例

如何利用“单例模式”配合闭包确保在单页应用中全局仅存在一个 WebSocket 长连接实例

来源:互联网 2026-04-21 14:10:03

如何利用单例模式与闭包确保单页应用全局仅有一个WebSocket连接实例 为何不能直接多次调用 new WebSocket() 在单页应用中,若每个页面或组件随意使用 new WebSocket(url),将导致多个物理连接同时存在。其后果是服务端会识别为多个独立客户端,资源占用倍增,消息广播也可能

如何利用单例模式与闭包确保单页应用全局仅有一个WebSocket连接实例

如何利用“单例模式”配合闭包确保在单页应用中全局仅存在一个 WebSocket 长连接实例

为何不能直接多次调用 new WebSocket()

在单页应用中,若每个页面或组件随意使用 new WebSocket(url),将导致多个物理连接同时存在。其后果是服务端会识别为多个独立客户端,资源占用倍增,消息广播也可能重复推送给同一用户。重连逻辑将变得难以统一管理。在 uni-app、Taro 等跨端框架中,情况更为复杂——new WebSocket() 这一原生 API 仅在 H5 环境有效,在小程序及 App 端并不可用。这意味着,直接使用该方式将破坏跨端行为的一致性。

长期稳定更新的攒劲资源: >>>点此立即查看<<<

闭包单例如何防止多次初始化

核心思路是利用立即执行函数表达式(IIFE)将 instance 变量封闭在内部作用域,外部无法直接修改。只有首次调用 getInstance() 时才会真正创建连接实例:

const WebSocketSingleton = (function () {
  let instance = null
  return {
    getInstance: function (url) {
      if (!instance) {
        // 此处需使用平台兼容的 API,例如 uni-app 应使用 uni.connectSocket
        instance = {
          url,
          socket: null,
          connect() {
            uni.connectSocket({ url })
            uni.onSocketOpen(() => { /* 保存引用 */ })
            uni.onSocketMessage((e) => { /* 向监听者转发消息 */ })
          },
          send(data) { uni.sendSocketMessage({ data }) }
        }
      }
      return instance
    }
  }
})()
  • 当再次调用 WebSocketSingleton.getInstance('wss://...') 时,不会新建连接,而是直接返回已创建的 instance
  • 需注意:即使传入不同的 url,闭包内的判断逻辑也不会覆盖原有实例。这虽可避免意外覆盖,但也可能带来隐患——若调用方传入不一致的 url,闭包可能误判为需要新建实例,导致意料之外的新连接。因此,最佳实践是确保所有调用传入的 url 完全一致。
  • 若应用需支持多个不同的 WebSocket 端点(例如区分测试与生产环境),建议将 url 提取至统一配置层管理,而非在每次调用 getInstance 时动态传入。

uni-app 中必须使用 uni.connectSocket

在 uni-app 生态中,uni.connectSocket 是官方提供的跨端统一 API,但其在不同平台的行为存在差异,使用时需注意:

  • 调用时机应在页面的 onReady 生命周期之后。若在 onLoad 阶段调用,在 App 端很可能失败。
  • URL 协议必须为 wss://。小程序平台会强制校验,ws:// 协议仅可在 H5 环境下用于本地调试。
  • 查询参数需经过 encodeURIComponent 编码。例如参数 token=abc+def 若不编码,可能导致连接意外中断。
  • 发送消息前,必须等待 uni.onSocketOpen 事件触发。否则直接调用发送接口会报错 fail websocket not connected

断开重连与状态清理易被忽视的细节

实现单例并不代表连接永久有效。实际场景中,应用切换至后台、网络切换或小程序被系统回收等,都会触发 uni.onSocketClose 事件。此时单例中的 instance.socket 可能仍不为 null,若后续直接调用 send 方法,将静默失败且难以追踪。

  • 因此,每次在 uni.onSocketCloseuni.onSocketError 事件触发后,必须手动清理状态,将 instance.socket 重置为 null。
  • 重连机制不宜简单使用固定间隔的 setTimeout。更健壮的做法是采用指数退避策略:例如首次重连等待 1 秒,第二次等待 3 秒,第三次等待 9 秒……通常最多尝试 5 次。
  • 在 App 和小程序的 onHide 生命周期中,应主动调用 uni.closeSocket() 并重置所有连接状态。否则用户切回应用时,连接可能已失效,但应用层仍显示“已连接”,导致后续操作全部失败。

闭包单例模式仅保证了“实例的唯一性”。连接本身的活性维持、错误恢复以及与应用生命周期的同步,仍需开发者手动完善。遗漏这些关键逻辑,单例便只是一个看似整洁、实则脆弱的空壳。

侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述

热游推荐

更多
湘ICP备14008430号-1 湘公网安备 43070302000280号
All Rights Reserved
本站为非盈利网站,不接受任何广告。本站所有软件,都由网友
上传,如有侵犯你的版权,请发邮件给xiayx666@163.com
抵制不良色情、反动、暴力游戏。注意自我保护,谨防受骗上当。
适度游戏益脑,沉迷游戏伤身。合理安排时间,享受健康生活。