前些天因為一個需求,必須要改用 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
回調存起來了,等到收到信息後再取出來調用。
(完)