icxiaoyanz

icxiaoyanz

x

讓 WebSocket 通訊像 Http 一樣簡單

前些天因為一個需求,必須要改用 WebSocket 進行通訊(為了繞開瀏覽器跨域限制),但是前面使用的接口都是用 Http 的。

心裡正想着可能要大改動了……

哎嘿,怎麼著,我看着之前寫好的一個個請求調用方法:傳參,await 等待,返回數據。

WebSocket 不也是得這樣嗎?發送數據,返回數據。只要把 WebSocket 的 send 方法套一個函數,然後 Promise 化,就可以像 Http 一樣使用了。

實現#

實現也很容易,這裡使用了 @vueuse/coreuseWebSocket 進行封裝。

import { useWebSocket } from '@vueuse/core'
import { toast } from 'vue-sonner'

interface WebSocketHandler {
  resolve: (data: any) => void
  reject: (data: any) => void
}

const messageHandlers = new Map<string, WebSocketHandler>()

const ws = useWebSocket(
  'ws://localhost:10000/ws',
  {
    autoReconnect: {
      delay: 2000,
      retries: 3,
    },
    heartbeat: {
      interval: 30000,
      pongTimeout: 3000,
      responseMessage: 'pong',
    },
    onMessage: (_, event) => {
      if (!event.data.startsWith('{"id"')) return
      
      const response = JSON.parse(event.data)
      const handler = messageHandlers.get(response.id)
      if (!handler) return

      const isSuccess = response.code === 200
      if (isSuccess) handler.resolve(response.data)
      else {
        toast.warning(response.message)
        handler.reject(new Error(response.message))
      }
    }
  }
)

export function wsFetch<T>(params: T) {
  return new Promise<T>((resolve, reject) => {
    if (ws.status.value !== 'OPEN') {
      reject(new Error('WebSocket is not connected'))
      return
    }

    const id = getRequestId()

    ws.send(JSON.stringify({ ...params, id }))
    messageHandlers.set(id, { resolve, reject })
  })
}

function getRequestId() {
  return Date.now().toString() + Math.random().toString(36).slice(2, 9)
}

這裡其實就是把 Promise 的 resolvereject 回調存起來了,等到收到信息後再取出來調用。

(完)

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。