如何在socket.io的connection作用域外跨文件访问socket实例
Socket.io 跨文件访问socket实例的几种最优方案
针对需要在socket实例上挂载自定义用户数据、且跨文件访问的场景,推荐以下两种落地性强的方案:
方案1:闭包工厂函数(最常用、无额外依赖)
适合业务逻辑拆分到不同模块、仅在事件回调中需要访问socket的场景,不需要额外维护全局存储,性能最优。
实现代码
message.js 导出工厂函数,接收socket实例后返回实际的事件处理逻辑:
// message.js module.exports = (socket) => { // 实际的消息处理逻辑,闭包内可直接访问当前连接的socket实例 return (payload) => { try { // 可直接读取socket上挂载的自定义属性 console.log(socket.id, socket.uid) // 其他业务逻辑 } catch (error) { console.log(error) } } }
index.js 连接建立时传入socket实例,拿到绑定后的处理函数绑定事件:
const createMessageHandler = require('./message') io.on("connection", socket => { // 先挂载自定义用户数据 socket.uid = "ABC_NAME" // 传入socket实例,获取绑定了当前连接的处理函数 const onMessageReceived = createMessageHandler(socket) socket.on("message", onMessageReceived) })
方案2:全局Map存储socket映射
适合需要在非事件回调的其他业务模块中随时访问socket的场景,比如定时给指定用户推送消息。
实现代码
先新增全局存储模块socket-store.js,维护socket实例映射:
// socket-store.js const socketMap = new Map() // 新增socket实例 exports.set = (socketId, socket) => socketMap.set(socketId, socket) // 获取socket实例 exports.get = (socketId) => socketMap.get(socketId) // 断开连接时删除,避免内存泄漏 exports.delete = (socketId) => socketMap.delete(socketId)
index.js 连接建立和断开时更新存储:
const socketStore = require('./socket-store') const onMessageReceived = require('./message') io.on("connection", socket => { socket.uid = "ABC_NAME" // 存入全局存储 socketStore.set(socket.id, socket) socket.on("message", (payload) => onMessageReceived(payload, socket.id)) // 断开连接时清理 socket.on("disconnect", () => socketStore.delete(socket.id)) })
message.js 按需从全局存储中读取socket:
// message.js const socketStore = require('./socket-store') module.exports = (payload, socketId) => { try { const socket = socketStore.get(socketId) console.log(socket.id, socket.uid) // 其他业务逻辑 } catch (error) { console.log(error) } }
关于你提到的栈溢出问题
你尝试通过改写socket.on方法自动注入socket参数的思路本身是可行的,出现Maximum call stack size exceeded是因为你改写方法时内部递归调用了原始的socket.on,没有正确保留原始方法的引用导致死循环,该方案侵入性较强,不推荐在生产环境使用。
内容的提问来源于stack exchange,提问作者Alok Prakash
相关产品推荐
相关产品推荐

