1,使用方式
const ws = websocket({
url: '/websocket',
onmessage: e => {
console.log(e)
}
})
ws.close()
2,源码如下
type TimeoutHandle = ReturnType<typeof setTimeout>
interface Fn<T = any, R = T> {
(...arg: T[]): R
}
interface IOptions {
url: string
token?: string
heart_time?: number
check_time?: number
lock_time?: number
onmessage: Fn<any, any>
onerror?: Fn<any, any>
onopen?: Fn<any, any>
onclose?: Fn<any, any>
}
const websocket = (options: IOptions) => {
class Ws {
public ws: WebSocket | undefined
private readonly baseUrl: string = import.meta.env.VITE_WS_BASE_API as string
private readonly url: string | undefined
private readonly onmessage: Fn<any, any>
private readonly onerror?: Fn<any, any>
private readonly onopen?: Fn<any, any>
private readonly onclose?: Fn<any, any>
private readonly token: string | undefined = tokenCookies.get()
private readonly heart_time: number = 3000
private readonly check_time: number = 3000
private readonly lock_time: number = 4000
private h_timer: TimeoutHandle | undefined
private c_timer: TimeoutHandle | undefined
private l_timer: TimeoutHandle | undefined
private isLock: boolean = false
constructor(options: IOptions) {
const { url, token, heart_time, check_time, lock_time } = options
const { onmessage, onerror, onopen, onclose } = options
if (!url || !onmessage) {
const message = !url ? '链接url' : '回调函数onmessage'
throw new Error(`socket${message}不能为空`)
}
this.url = this.baseUrl + url
this.onmessage = onmessage
if (!!onerror) {
this.onerror = onerror
}
if (!!onopen) {
this.onopen = onopen
}
if (!!onclose) {
this.onclose = onclose
}
this.token = token || tokenCookies.get()
this.heart_time = heart_time || 3000
this.check_time = check_time || 3000
this.lock_time = lock_time || 4000
this.wsInit()
}
public wsInit(): void {
if (!this.url || !this.token) {
return
}
const url = this.url + '?token=' + this.token
const ws = new WebSocket(url)
ws.onopen = e => {
this.heartCheck()
if (!!this.onopen) {
this.onopen(e)
}
}
ws.onclose = e => {
if (!!this.token) {
this.reconnect()
}
if (!!this.onclose) {
this.onclose(e)
}
}
ws.onerror = e => {
if (!!this.token) {
this.reconnect()
}
if (!!this.onerror) {
this.onerror(e)
}
}
ws.onmessage = e => {
this.heartCheck()
this.onmessage(e)
}
this.ws = ws
}
private heartCheck(): void {
this.clearTimeout()
this.h_timer = setTimeout(() => {
;(this.ws as WebSocket).send('type:ping')
this.c_timer = setTimeout(() => {
if ((this.ws as WebSocket).readyState !== 1) {
this.close()
}
}, this.check_time)
}, this.heart_time)
}
private reconnect(): void {
if (this.isLock) {
return
}
this.isLock = true
this.l_timer && clearTimeout(this.l_timer)
this.l_timer = setTimeout(() => {
this.wsInit()
this.isLock = false
}, this.lock_time)
}
private clearTimeout(): void {
this.h_timer && clearTimeout(this.h_timer)
this.c_timer && clearTimeout(this.c_timer)
}
public close(): void {
;(this.ws as WebSocket).close()
this.clearTimeout()
}
}
return new Ws(options)
}
export default websocket