在 Redux Saga 中重用 websocket 连接对象

Reusing websocket connection object in Redux Saga

我有问题。我在 React Redux eventChannel 内的 websocket 的帮助下连接到服务器。我从服务器接收事件没有问题,但我无法将事件发送到服务器。我知道,我需要获取我在 eventChannel 中创建的 websocket 连接对象,例如从 React 组件发送事件。

export function* wsWatcher() {
    yield takeEvery("LOGIN_SUCCESS", wsConnectionWorker);
}

function* wsConnectionWorker() {
    const channel: EventChannel<boolean> = yield call(initWebsocket);
    while (true) {
        const action: Action<any> = yield take(channel);
        yield put(action);
    }
}

function initWebsocket(): EventChannel<any> {
    return eventChannel((emitter) => {

    let id: string | undefined;
    let intervalId: number;

    const initConnection = () => {
        const connectionUrl: string = "ws://localhost:4000" 
            
        let ws = new WebSocket(connectionUrl);
        
        ws.onopen = () => {
            id && ws.send(JSON.stringify({ type: "GET_USER_ID", id }));

            intervalId = window.setInterval(() => {
                ws.send(JSON.stringify({ type: "PING" }))
            }, 30000)
        };

        ws.onclose = (e) => {
            console.log("Reconnect in 4s");
            intervalId && clearInterval(intervalId);
            id && setTimeout(initConnection, 4000); 
        };
    };

    initConnection();

    return () => {
        console.log("Socket off");
    };
});
}

提前致谢

您可以在模块的范围内创建一个变量,并在第一次初始化后将连接对象存储在其中。以后需要连接时,只需使用此变量即可。

这是有效的,因为模块缓存在 nodejs 中。也就是说,运行 中模块中的代码仅在首次导入时使用,之后的导入使用缓存的模块。

如需进一步参考,请阅读更多内容:Modules Caching

您也可以为此设置一个函数,例如此代码中的 getConnection 函数。每当您需要 websocket 连接时,调用此函数,它只会创建一次连接。

export function* wsWatcher() {
    yield takeEvery("LOGIN_SUCCESS", wsConnectionWorker);
}

function* wsConnectionWorker() {
    const channel: EventChannel<boolean> = yield call(getConnection);
    while (true) {
        const action: Action<any> = yield take(channel);
        yield put(action);
    }
}

// store the EventChannel after first init
let wsConnection: EventChannel<any> = null;

// create WS connection on first call
// reuse that connection in further calls
function getConnection(): EventChannel<any>{
  if(!wsConnection){
    wsConnection = initWebsocket();
  return wsConnection;
}

function initWebsocket(): EventChannel<any> {
    return eventChannel((emitter) => {

    let id: string | undefined;
    let intervalId: number;

    const initConnection = () => {
        const connectionUrl: string = "ws://localhost:4000" 
            
        let ws = new WebSocket(connectionUrl);
        
        ws.onopen = () => {
            id && ws.send(JSON.stringify({ type: "GET_USER_ID", id }));

            intervalId = window.setInterval(() => {
                ws.send(JSON.stringify({ type: "PING" }))
            }, 30000)
        };

        ws.onclose = (e) => {
            console.log("Reconnect in 4s");
            intervalId && clearInterval(intervalId);
            id && setTimeout(initConnection, 4000); 
        };
    };

    initConnection();

    return () => {
        console.log("Socket off");
    };
});
}