前些天因为一个需求,必须要改用 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 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 的 resolve
和 reject
回调存起来了,等到收到信息后再取出来调用。
(完)