【useWebsocket】vue3+vite封装websocket hooks

本文介绍了如何在Vue应用中使用WebSocket进行通信,包括封装接口、设置连接选项、处理连接状态变化、心跳检测以及断开连接的逻辑。同时提及了与系统存储模块的集成和参数编码方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不废话了,直接上干货。可直接食用
ts刚开始用,不合理的地方欢迎指导,虚心请教

import { onUnmounted, ref } from 'vue'

import { useSystemStore } from '@/store/modules/systemStore/systemStore'

interface QueryType {
  url: string //url
  options?: OptionsType //配置
  params?: object //url参数
  onmessage?: Function //回调函数
}
interface OptionsType {
  maxReconnect?: number //最大重连次数, -1 标识无限重连
  interval?: number //心跳间隔
  timeout?: number //  响应超时时间
  pingMessage?: string // 心跳请求信息
}
const defaultOptions = {
  maxReconnect: 6,
  interval: 30 * 1000,
  timeout: 10 * 1000,
  pingMessage: 'ping'
}

/**
 * websocket封装
 * @param {object} param0
 * @returns  serverMessage, sendMessage, destroySocket
 */
export default function useWebSocket({ url, options = {}, params, onmessage }: QueryType) {
  const OPTION = { ...defaultOptions, ...options }
  let socket: WebSocket | null = null //websocket实例
  let pingTimeoutObj: NodeJS.Timeout | null = null //延时发送心跳的定时器
  let pongTimeoutObj: NodeJS.Timeout | null = null //接收心跳响应的定时器
  let reconnectCount: number = 0 // 重连尝试次数
  let lockReconnect: Boolean = false // 重连锁,避免多次重连

  const token = useSystemStore().getToken

  // 初始化连接socket
  function initWebSocket() {
    const VITE_APP_SOCKET_API = import.meta.env.VITE_APP_SOCKET_API
    const _params = objectToEncodeQuery(params)
    const wsUri = `${VITE_APP_SOCKET_API}${url}?token=${token}` + _params

    socket = new WebSocket(wsUri)

    // 连接成功
    socket.onopen = onOpen
    // 连接错误
    socket.onerror = onError
    // 接收信息
    socket.onmessage = onMessage
    // 连接关闭
    socket.onclose = onClose
  }

  /**
   * 连接成功事件
   */
  function onOpen() {
    // 开启心跳
    startHeartbeat()
    reconnectCount = 0
  }

  /**
   * 连接失败事件
   * @param e
   */
  function onError(e) {
    console.error(`WebSocket connection error:${e.code} ${e.reason} ${e.wasClean}`)
    reconnect()
  }

  /**
   * 连接关闭事件
   * @param e
   */
  function onClose() {
    reconnect()
  }

  /**
   * 重新连接
   */
  function reconnect() {
    if (!token) {
      return
    }

    if (lockReconnect || (OPTION.maxReconnect !== -1 && reconnectCount > OPTION.maxReconnect)) {
      return
    }

    lockReconnect = true
    setTimeout(() => {
      reconnectCount++
      // 建立新连接
      initWebSocket()
      lockReconnect = false
    }, 5000)
  }

  /**
   * 清空定时器
   */
  function clearTimeoutObj() {
    pingTimeoutObj && clearTimeout(pingTimeoutObj)
    pongTimeoutObj && clearTimeout(pongTimeoutObj)
  }

  /**
   * 开启心跳
   */
  function startHeartbeat() {
    console.log('startHeartbeat')
    // 清空定时器
    pingTimeoutObj && clearTimeout(pingTimeoutObj)
    // 延时发送下一次心跳
    pingTimeoutObj = setTimeout(() => {
      sendMessage(OPTION.pingMessage)
    }, OPTION.interval)
  }

  const serverMessage = ref()
  /**
   * 接收服务器推送的信息
   * @param msgEvent
   */
  function onMessage(msgEvent) {
    console.log('msgEvent')
    // 收到服务器信息,心跳重置并发送
    startHeartbeat()
    const text = msgEvent.data

    if (text === 'pong') {
      return
    }
    const data = JSON.parse(msgEvent.data)
    serverMessage.value = data.data
    onmessage && onmessage(data.data)
  }

  function sendMessage(message: string) {
    // 如果连接正常
    if (socket && socket.readyState === 1) {
      // 这里发送一个心跳,后端收到后,返回一个心跳消息,
      socket.send(message)
      // 心跳发送后,如果服务器超时未响应则断开,如果响应了会被重置心跳定时器
      pongTimeoutObj && clearTimeout(pongTimeoutObj)
      pongTimeoutObj = setTimeout(() => {
        socket && socket.close()
      }, OPTION.timeout)
    } else {
      // 否则重连
      reconnect()
    }
  }
  /**
   * 销毁socket
   */
  function destroySocket() {
    if (socket) {
      lockReconnect = true
      socket.close()
      clearTimeoutObj()
    }
  }
  //  断开连接
  onUnmounted(() => {
    destroySocket()
  })

  /**
   * 对象转url参数
   */
  function objectToEncodeQuery(query: object | undefined): string {
    if (!query) return ''

    const params = Object.keys(query)
      .filter(key => query[key])
      .map(key => {
        return encodeURIComponent(key) + '=' + encodeURIComponent(query[key])
      })
      .join('&')

    return params
  }

  initWebSocket()

  return { serverMessage, sendMessage, destroySocket }
}

<think>好的,我现在需要处理用户关于React和Vue性能对比测试的问题。用户希望在不同浏览器,特别是国产浏览器中,测试两者的CPU、内存消耗以及界面流畅度,并生成包含17项数据的表格。首先,我需要明确用户的具体需求,然后制定一个详细的测试方案。 用户提到的测试场景包括1万行数据,每100ms刷新一次,持续4小时以上。这看起来像是一个高频率更新的场景,对前端框架的性能压力较大。需要考虑到浏览器的渲染机制以及框架的优化策略。国产浏览器可能使用不同的内核,比如360浏览器可能使用IE或Chrome内核,UC浏览器可能有自己的优化,这些都需要在测试环境中明确。 接下来,我需要参考用户提供的引用内容。引用1提到Vue的列表对比更高效,而React会移动更多节点,这可能影响大数据量下的性能。引用2和3讨论了Vue和React在响应式系统和性能优化上的差异,比如Vue的依赖收集是自动的,而React需要手动处理,这可能影响内存和CPU的使用。引用4和5提到了移动端支持,但用户当前需求集中在浏览器性能,这部分可能暂时不需要考虑。 首先,确定测试指标。用户需要17项数据,可能需要将指标分为前端、后端、综合三类。前端包括内存占用、CPU使用率、FPS、渲染时间、响应延迟、节点操作效率、GC频率。后端可能包括CPU、内存、网络I/O、请求错误率。综合部分则是数据更新稳定性、内存泄漏风险、首屏加载时间、国产浏览器兼容性、长时间运行稳定性、框架体积、社区支持度。这样正好17项。 然后是测试环境搭建。需要选择React和Vue的最新版本,比如React 18和Vue 3.4。测试数据方面,生成1万行数据,结构可能需要包含多个字段来模拟真实场景。定时器每100ms刷新数据,这可能会对虚拟DOM或响应式系统造成压力。需要确保数据更新的方式一致,比如使用随机部分数据更新而非全量替换,以模拟实际应用。 在浏览器选择上,除了Chrome、Firefox,还需要包括国产浏览器如360极速、QQ浏览器、UC浏览器,并注明它们的内核版本,因为不同内核可能导致性能差异。测试工具方面,Chrome DevTools和Firefox Profiler可以监测性能,但国产浏览器的开发者工具可能有限,可能需要使用系统级监控工具如Windows的任务管理器或Linux的top命令来记录CPU和内存。对于流畅度,使用requestAnimationFrame计算FPS,以及自定义的时间戳记录渲染时间。 测试步骤需要详细,包括环境配置、数据生成、性能埋点、测试执行、数据收集和分析。每个步骤都要确保一致性,比如相同的硬件、网络条件,避免外部干扰。多次测试取平均值以减少误差。 可能遇到的问题包括国产浏览器的兼容性问题,比如某些API支持不同,或者CSS渲染差异。需要提前检查并处理。另外,长时间运行测试可能导致内存泄漏,需要在代码中避免,比如及时清理定时器和事件监听器。 在分析结果时,根据引用内容,Vue可能在列表更新时更高效,因为其差异对比策略更智能,而React可能需要更多的节点操作,导致更高的CPU使用。Vue的响应式系统自动依赖收集可能减少不必要的渲染,而React的Hook可能在频繁更新时带来更多的GC压力,影响内存表现。不过,React的灵活性可能允许更多的手动优化,比如使用memo或useMemo来减少重复渲染。 生成表格时,需要确保每个指标都有React和Vue的数据,并注明测试条件和环境。例如,在内存占用方面,Vue可能较低,而React可能因为频繁的组件重建而较高。流畅度方面,FPS越高越好,Vue可能在这方面表现更好。 最后,在回答用户时,需要总结关键差异,指出Vue在数据驱动场景下的优势,React在复杂交互中的灵活性,并给出框架选择的建议,根据项目需求权衡性能和开发体验。</think>### React vs Vue 性能对比测试方案 #### 一、测试环境设计 1. **框架版本** - React 18.x(最新稳定版) - Vue 3.4.x(最新稳定版) 2. **测试场景** - 数据量:10,000行数据(动态可调) - 更新频率:每100ms触发全量数据更新 - 持续时长:每组测试4小时 3. **浏览器覆盖** - 主流浏览器:Chrome 120+、Firefox 120+ - 国产浏览器:360极速浏览器(Chromium 115内核)、QQ浏览器(Blink内核)、UC浏览器(U4内核) 4. **监控指标工具** - **前端性能**:Chrome DevTools Performance面板、Firefox Profiler - **系统资源**:Windows任务管理器/Linux `top`命令(记录CPU/内存) - **流畅度**:`requestAnimationFrame`计算FPS,自定义时间戳埋点 --- #### 二、性能指标表格(17项) | **类别** | **指标** | **React** | **Vue** | **测试条件** | |----------------|------------------------|-----------|---------|----------------------------------| | **前端性能** | 内存占用峰值(MB) | - | - | 10k行数据渲染时 | | | CPU使用率均值(%) | - | - | 持续更新期间 | | | FPS(帧率) | - | - | 动态更新阶段 | | | DOM渲染耗时(ms) | - | - | 单次数据更新周期 | | | 响应延迟(ms) | - | - | 操作触发到界面反馈 | | | 虚拟DOM操作效率(次/s)| - | - | Diff算法执行频率[^1] | | | GC频率(次/分钟) | - | - | 垃圾回收触发次数[^2] | | **后端性能** | CPU占用峰值(%) | - | - | 数据推送压力下 | | | 内存占用增长(MB) | - | - | 4小时运行后差值 | | | 网络I/O负载(MB/s) | - | - | WebSocket长连接数据量 | | | 请求错误率(%) | - | - | 数据推送失败比例 | | **综合表现** | 数据更新稳定性(标准差)| - | - | 渲染时间波动 | | | 内存泄漏风险 | - | - | 4小时后内存增长率 | | | 首屏加载时间(s) | - | - | 10k数据初始渲染 | | | 国产浏览器兼容性 | - | - | 功能异常/渲染错误次数 | | | 长时间运行稳定性 | - | - | 卡顿/崩溃频率 | | | 框架体积(gzip KB) | - | - | 生产环境构建大小 | | | 社区支持度 | - | - | 问题解决速度/文档覆盖[^3] | --- #### 三、关键差异预测(基于引用分析) 1. **列表更新效率** - **Vue**:采用两端到中间比对策略,移动节点更高效[^1] - **React**:从左到右全量对比,可能产生更多DOM操作 2. **响应式系统** - **Vue**:依赖自动收集,组件级优化减少无效渲染[^2] - **React**:依赖手动声明(如`useMemo`),频繁更新可能引发GC压力 3. **内存管理** - **Vue**:组合式API单实例调用,内存占用更稳定[^2] - **React**:Hooks多次执行可能增加临时对象生成 --- #### 四、实施步骤建议 1. **环境配置** ```bash # React 示例项目 npx create-react-app react-perf-test # Vue 示例项目 npm init vue@latest vue-perf-test ``` 2. **数据生成逻辑** ```javascript // 生成10,000行测试数据 const generateData = () => { return Array.from({ length: 10000 }, (_, i) => ({ id: i, value: Math.random() * 100, timestamp: Date.now() })); }; ``` 3. **性能埋点示例** ```javascript // 记录渲染时间 let startTime; useEffect(() => { startTime = performance.now(); return () => { const renderTime = performance.now() - startTime; logToServer(renderTime); // 上报到后端 }; }, [data]); ``` --- #### 五、注意事项 1. **国产浏览器适配** - 360浏览器需关闭“极速模式兼容性优化” - UC浏览器需启用`硬件加速`选项 2. **误差控制** - 每组测试重复3次取均值 - 关闭浏览器插件/系统后台进程 3. **代码优化建议** - **React**:使用`React.memo` + `useMemo`减少渲染 - **Vue**:利用`v-once` + `shallowRef`控制响应式深度 --- #### 六、扩展建议 1. **进阶测试场景** - 添加复杂交互(拖拽、筛选) - 混合SSR(如Next.js vs Nuxt.js) 2. **工具链对比** - 构建工具(Webpack vs Vite) - 状态管理(Redux vs Pinia) ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值