前些天因为一个需求,必须要改用 WebSocket 进行通讯(为了绕开浏览器跨域限制),但是前面使用的接口都是用 Http 的。
心里正想着可能要大改动了……
哎嘿,怎么着,我看着之前写好的一个个请求调用方法:传参,await
等待,返回数据。
WebSocket 不也是得这样吗?发送数据,返回数据。只要把 WebSocket 的 send
方法套一个函数,然后 Promise 化,就可以像 Http 一样使用了。
実装#
実装も簡単で、ここでは @vueuse/core
の useWebSocket
を使ってラップしています。
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 は接続されていません'))
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 の resolve
と reject
コールバックを保存しておき、情報を受け取った後に取り出して呼び出しています。
(完)