我应该使用全局变量在整个服务器上共享socket.io实例吗

时间:2018-10-28 10:58:44

标签: node.js websocket socket.io

以下是我的node.js应用程序中的server.js文件。我希望我的服务器上的其他文件可以访问我的socket.io实例,以便从我的API (listingRoutesApi, userRoutesApi etc.) (refer to code)发出事件。

我的问题是在创建服务器之前就声明了路由;但是,socket.io实例是在创建服务器后创建的。

我使用的解决方案是声明一个全局io变量,该变量将使我能够从Web应用程序中的任何位置发出事件,例如:

global.io.of('/analytics').to(listing._id).emit('message', "There was a post.");

我的问题是:这样做是否有任何陷阱/危险,并且从长期来看,我会遇到任何可扩展性问题吗?此外,还有更好的方法可以实现我的目标吗?

server.js文件中的代码:

const app = express();    

app.use('/api', listingRoutesApi);
app.use('/api', userRoutesApi);
app.use('/api', imageRoutesApi);
// ...plenty more endpoints here...

app.use(serveStatic(path.join(__dirname, "/dist")));
app.use(history());
app.use(serveStatic(path.join(__dirname, "/dist")));

const server = app.listen(port, () => { console.log('server started ' + port); });

/* Start socket. */
global.io = socketio(server);

const analytics = global.io.of("/analytics");

analytics.on('connection', (socket) => {
    socket.on('join', (data) => {
        socket.join(data.room);
        analytics.in(data.room).emit('message', `New user joined ${data.room}`);
    });
    socket.on('leave', (data) => {
        analytics.in(data.room).emit('message', `User leaving ${data.room}`);
        socket.leave(data.room);
    });
    socket.on('disconnect', () => {
        console.log('user disconnected');
    });
});

我之所以问这个问题,是因为this SO post通过声明一个getIOInstance函数并将其传递给需要它的所有模块来回答类似的问题。虽然它可以正常工作,但感觉并不优雅,并且由于我希望在我的应用程序中只拥有一个完全相同的socket.io实例,因此显得有些不必要。

此外,我认为我面临的挑战是非常普遍的挑战。但是,我无法找到许多解决方案来解决这个问题,而没有一个建议使用全局变量。

1 个答案:

答案 0 :(得分:2)

Node.js是模块化环境。假定模块可以解决全局变量所具有的一些缺陷。

如果只需要一个实例,则模块自然会提供单例实例:

app.js

module.export = express();

server.js

const app = require('./app');

module.export = app.listen(...);

socketio.js

const server = require('./server');

module.export = socketio(server);

index.js

const app = require('./app');
const io = require('./socketio');
...

Express还为应用程序全局依赖项application settings table提供了一个容器。它可以在可用的应用程序实例的任何地方使用,例如作为中间件中的req.app.get(...)。如果也是单例,那么在中间件外部访问Express应用程序实例也不会成为问题:

app.js

module.export = express();

index.js

const app = require('./app');

...

const server = app.listen(...);
const io = socketio(server);

app.set('io', io);

// available as req.app.get('io') inside middlewares
// and as require('./app).get('io') outside them