前端使用redux集中处理webSocket消息推送存在并发问题解决方法

        前端在处理后端通过webSocket推送消息的时候,容易出现后端同时发送两条不同type的情况(如:第一条消息发送过来的时间是2024/03/15 09:22:01.360;第二条消息发送过来的时间2024/03/15 09:22:01.361),如果用redux统一处理类型并分发对应的reducer,就会出现同时调用一个action,并且第二条消息把第一条消息覆盖的情况。

        针对这一问题,前端可以使用队列来解决,声明一个空数组,来一条消息就往数组里去push,再写一个定时器,每隔100毫秒取数组最后一条消息去触发redux的action(先进先出),就不会出现同时触发的情况了。代码示例:

// 自定义hooks
const useWebsocket = ({ url }) => {
    const ws = useRef<any>(null)
    const [wsData, setMessage] = useState('')
    const [readyState, setReadyState] = useState({ key: 0, value: '正在链接中' })
    const token = getToken()
    const cacheWsArr = useRef<any[]>([])

    const handleMessage = () => {
        setInterval(() => {
            if (cacheWsArr.current.length > 0) {
                // 每隔一百毫秒从数组最后一项取
                const data = cacheWsArr.current.shift()
                setMessage(JSON.stringify(data))
            }
        }, 100)
    }

    const creatWebSocket = () => {
        const stateArr = [{ key: 0, value: '正在链接中' }, { key: 1, value: '已经链接并且可以通讯' }, { key: 2, value: '连接正在关闭' }, { key: 3, value: '连接已关闭或者没有链接成功' }]
        try {
            getWsUrl().then(res => {
                if (res && res.code !== 200) return
                ws.current = new WebSocket(`${res.data}${url}`, [token])
                ws.current.onopen = (_e) => {
                    setReadyState(stateArr[ws.current?.readyState ?? 0])
                }
                ws.current.onclose = (e) => {
                    setReadyState(stateArr[ws.current?.readyState ?? 0])
                }
                ws.current.onerror = (e) => {
                    setReadyState(stateArr[ws.current?.readyState ?? 0])
                }
                ws.current.onmessage = (e) => {
                    const obj = JSON.parse(e.data)
                    const data = {
                        ...obj,
                        type: obj.type + `_${new Date().getTime()}`,
                    }
                    // 往缓存消息的数组中添加!!
                    cacheWsArr.current.push(data)
                }
            })
        } catch (error) {
            console.log(error)
        }
    }

    const webSocketInit = () => {
        if (!ws.current || ws.current.readyState === 3) {
            creatWebSocket()
            // 初始化时创建定时器
            handleMessage()
        }
    }

    //  关闭 WebSocket
    const closeWebSocket = () => {
        ws.current?.close()
    }

    const reconnect = () => {
        try {
            closeWebSocket()
            ws.current = null
            creatWebSocket()
        } catch (e) {
            console.log(e)
        }
    }

    useEffect(() => {
        if (token) {
            webSocketInit()
        }
        return () => {
            ws.current?.close()
        }
    }, [ws, token])

    return {
        wsData,
        readyState,
        closeWebSocket,
        reconnect
    }
}
export default useWebsocket

欢迎大佬们提出优化意见~

  • 13
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值