如何创build一个可重用的Socket.IO模块

我有创build一个暴露我的Socket.IO库function的模块的麻烦:

const sio = require('socket.io'); module.exports = function(server) { const io = sio(server); return { register: function(namespace) { let nsp = io.of(namespace); nsp.on('connect', function(socket) { // ... } } } } 

现在的问题是如何在其他模块中使用这个? 在我的app.js

我使用Express创buildserver ,并可以使用require('./mysocketio')(server)实例化模块,但不能在其他模块中使用,因为服务器在那里不可用。 什么是解决这些循环依赖的好方法?

那么你可以通过各种方式来实现这些,比如:

  • 将对象设置为全局名称空间。 (改变全球需求护理)
  • 使用module.exports并要求其他文件中的对象。 (如果处理不当,会导致循环依赖问题)
  • 将实例作为parameter passing给控制器​​,同时在路由中要求它们。

myModule.js 模块,它提供了Socket.IO库的function

 const sio = require('socket.io'); module.exports = function(server) { const io = sio(server); return { register: function(namespace) { let nsp = io.of(namespace); nsp.on('connect', function(socket) { // ... } } } } 

FLow 1:在全局命名空间中设置模块。

app.js

 var app = require('express').createServer(); var io = require('./myModule')(app); global._io = io; app.listen(80) 

controller.js

 module.exports = function(io){ var that={}; /* * Private local variable * made const so that * one does not alter it by mistake * later on. */ const _io = global._io; that.myAction = function(req,res){ _io.register('newRoom'); res.send('Done'); } return that; } 

stream程2:传递模块作为参数。

app.js

 var app = require('express').createServer(); var io = require('./myModule')(app); require(./router.js)(app,io); app.listen(80); 

router.js

 /* * Contains the routing logic */ module.exports = function (app,io) { //passing while creating the instance of controller for the first time. var controller = require("./controller")(io); app.get('/test/about',controller.myAction); }; 

controller.js

 module.exports = function(io){ var that={}; const _io = io; that.myAction = function(req,res){ _io.register('newsRoom'); res.send('Done'); } // everything attached to that will be exposed // more like making public member functions and properties. return that; } 

stream程3:将io设置为全局。 因此不需要每次都通过服务器。

app.js

 var app = require('express').createServer(); require('./myModule')(app); require(./router.js)(app); app.listen(80); 

controller.js

 // no need to pass the server as io is already initialized const _io = require('./myModule')(); module.exports = function(io){ var that={}; that.myAction = function(req,res){ _io.register('newsRoom'); res.send('Done'); } return that; } 

myModule.js

 module.exports = function( server ) { const _io = global._io || require('socket.io')(server); if(global._io === undefined){ //initializing io for future use global._io = _io; } return { register: function(namespace) { let nsp = _io.of(namespace); nsp.on('connect', function(socket) { // ... } } } } 

也许,最简洁的方式是通过控制器作为参数,而要求在路线上。 虽然第三stream看起来很有希望,但是在改变全局命名空间的同时,应该充分注意。

这不是一个真正的循环依赖; 只是你的模块a)依赖于另一个不是全局可用的模块,b)你的模块可能被用在你的代码中的很多地方。

全球

一个可能的解决scheme(有缺点),就是加载你的模块一次,并将其附加到一个global: global.mysocketio = require('./mysocketio')(server);

这允许您在项目中的任何地方访问global.mysocketio,一旦它被加载。 这是我个人用于自己的logging器build设的结构; 我的logging器被用在我的代码周围的许多地方,所以我只是把它连接到global.log。

但是,全局的使用有点肮脏; 它给命名空间分离带来了问题(某些代码决定使用global.mysocketio本身),并创build一个“不可见”依赖; 其他代码只是假定某个全局将存在,并且find这些依赖关系并不那么容易。

出口

一个更好的解决scheme是只需要传递variables。 有很多方法可以做到这一点。 我知道你的app.js没有可用的服务器variables,但是肯定会以某种方式包含你的express-code。 如果你需要app.js提供的'server'或者'mysocketio',只需要从你创build'server'的模块中导出。 喜欢:

module.exports.expressServerVar = server;

只是我的2美分; 你强烈不同意我还是我错过重要的东西? 让我知道!

我会使用工厂或dependency injection。 你可以使用像jimple的东西。

但是这里有一个没有使用任何外部依赖的例子。 这绝不是最好的代码示例,但它应该有希望得到重点。 我仍然build议使用jimple而不是这个。

 // app.js var express = require('express'); var app = express(); var factory = require('./factory.js'); factory.setExpress(app); // This could also be done in the factory constructor. Or you could instanciate your express app in the factory.js class. // factory.js var socketIoModule = require('./your-socket-io-module.js') function Factory() { } Factory.prototype.setExpress = function(app) { this.app = app; } Factory.prototype.getSocketIOModule = function() { return socketIoModule(this.app); } // By exporting it this way we are making it a singleton // This means that each module that requires this file will // get the same instance of factory. module.exports = new Factory(); // some code that needs socket io module var factory = require('./factory.js'); function() { var socketIo = factory.getSocketIOModule(); socketIo.doStuff(); } 

我在我的应用程序中使用的方法是从启动脚本公开serverio实例,并在模块中重用它们

 // Setup servers. var http = require('http').Server(app); var io = require('socket.io')(http); // Setup application. require('./server/app')(app, express, io); // Start listening on port. http.listen(configs.PORT, function() { console.log("Listening on " + configs.PORT); }); 

在你的模块内部,你可以使用io实例来设置事件处理程序或发送事件,就像这样

 module.exports = { contest: function(io, contest) { var namespace = io.of('/' + contest.id); namespace.on('connection', function(socket) { socket.on('word', function(data) { ... }); }); } }; 

为你的样品

我会把这部分放在app.js或用于启动服务器的js文件中

 const sio = require('socket.io'); const io = sio(server); 

并将有这样的Socket.IO模块

 module.exports = function(server, io) { return { register: function(namespace) { let nsp = io.of(namespace); nsp.on('connect', function(socket) { // ... } } } } 

我的样品