在 Redux Saga 中重用 websocket 连接对象
Posted
技术标签:
【中文标题】在 Redux Saga 中重用 websocket 连接对象【英文标题】:Reusing websocket connection object in Redux Saga 【发布时间】:2021-09-16 04:57:18 【问题描述】:我有问题。我在 React Redux eventChannel 中的 websocket 的帮助下连接到服务器。我从服务器接收事件没有问题,但我无法将事件发送到服务器。我知道,我需要获取我在 eventChannel 中创建的 websocket 连接对象,以从反应组件发送事件。
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");
;
);
提前致谢
【问题讨论】:
【参考方案1】:您可以在模块的范围内创建一个变量,并在第一次初始化后将连接对象存储在其中。以后需要连接时,只需使用此变量即可。
这是可行的,因为模块缓存在 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");
;
);
【讨论】:
嗨!感谢您的回答。但我很困惑。当我导入 wsConnection 时,我有一个具有以下属性的对象:take、flush 和 close。我认为,它的 redux 传奇属性。我可以保存一个“ws”对象吗,我在这里得到:“let ws = new WebSocket(connectionUrl);”? 你可以。但是,如果您使用缓存的 WebSocket,则在向其中添加onopen
、onclose
事件侦听器时应该小心,因为这些事件侦听器可能已经存在。
所以我创建了一个全局变量,将 ws 变量保存到它并导出它?然后我可以导入它并使用我想要的方式?
是的,创建一个全局变量,最好也是一个函数getWs()
。 getWs
应该返回已经可用的实例或创建一个并返回。在这种情况下,您将不得不更改 onopen
和 onclose
逻辑。如果你能分享你想通过这个传奇实现的目标,我会修改我的代码。
我创建了一个变量,并在“let ws = new WebSocket()”字符串之后将 ws 对象保存到其中。例如,我现在可以导入它并在我的点击事件中使用它。我想要的是从我的反应组件访问 ws 以便将事件发送到服务器。创建全局变量有一点问题。如果我在组件内部使用这个变量(不在事件处理程序或其他东西中),它会说它仍处于连接状态。但在处理程序中一切都很好以上是关于在 Redux Saga 中重用 websocket 连接对象的主要内容,如果未能解决你的问题,请参考以下文章
无法弄清楚如何使用 redux-saga-test-plan 测试 redux-saga 功能
Redux Saga:使用 redux-saga-test-plan 和 jest 在我的 saga 中测试纯 javascript 函数