Require (the same instance of) socket.io in multiple modules

假如想象 提交于 2021-02-19 08:42:06

问题


I am a bit confused, about how to require and use modules in Node.js.

My scenario is the following:

I wrote a complete server in one single file, which uses Socket.io for realtime communication.

Now the index.js became pretty big, and I want to split the code into several modules to make it more managable.

For example I have some functions for serving a Survey to the clients, and getting back their answers. I put all those functions in a seperate module, and require it in the index.js. Works fine so far.

The only thing I am concerned about is, if there is another way to use the SAME socket instance inside the module.

My current coding looks like this:

index.js:

var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var Survey = require('./survey');

io.on('connection', function (client) {
    client.on('getCurrentQuestion', function (data) {
        Survey.getCurrentQuestion(parseInt(data.survey_id), client.id);
    });
});

server.listen(port, server_url, function () {
    Survey.init(io);
});

survey.js:

var io = null;

var Survey = {};

Survey.init = function(socketio) {
    io = socketio;
};

Survey.getCurrentQuestion = function(survey_id, socket_id) {
    var response = {
        status: "unknown",
        survey_id: survey_id
    };

    // [...] some code that processes everything

    // then uses Socket.io to push something back to the client
    io.sockets.in(socket_id).emit('getCurrentQuestion', response);
};

module.exports = Survey;

This way it works, but I'm not happy passing io inside an init function to the required module.

What would be "the right way" to do this?

If I require('socket.io') inside the survey module, will it be the same instance as in index.js?

How would I even require that, since it needs the server, which needs the app, which is created in index.js?

I am confused and hope that somebody can help me. Thanks!


回答1:


When you import a node.JS library you can also pass in objects. In your case the index.js file should be changed to the following:

//index.js
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var Survey = require('./survey')(io);

Then just change your survey.js code to take the io object:

//survey.js

module.exports = function (io) {
    var Survey = {};

    Survey.getCurrentQuestion = function(survey_id, socket_id) {
        var response = {
            status: "unknown",
            survey_id: survey_id
        };

        // [...] some code that processes everything

        // then uses Socket.io to push something back to the client
        io.sockets.in(socket_id).emit('getCurrentQuestion', response);
    };

    return Survey;
};

To answer your other question:

If you require('socket.io') inside the survey module, it will be a different instance from index.js.

EDIT

If you want a more modern way of doing it...You could use ES6 format and create a class to do this better:

'ES6 index.js

import SurveyClass from './Survey';
import * as express from 'express';
let app = express();
let server = require('http').createServer(app);
let io = require('socket.io')(server);
let MySurveyClass= SurveyClass(io);
let myInstance = new MySurveyClass();

myInstance.getCurrentQuestion(5, "some-socket-id");

'ES6 survey.js
export default class Survey{

    constructor(io){
        this.io= io;
    };


    getCurrentQuestion(survey_id, socket_id) {
        var response = {
            status: "unknown",
            survey_id: survey_id
        };

        // [...] some code that processes everything

        // then uses Socket.io to push something back to the client
        this.io.sockets.in(socket_id).emit('getCurrentQuestion', response);
    };




}



回答2:


When you do this in multiple modules:

var socketio = require('socket.io');

then it will be the same object for all requires.

But if you do this:

var io = require('socket.io')(server);

even if you have the same object in server in both places, io would be a different value because it would come from different invocations of the function returned by require('socket.io') even though those functions would be the same.

If you want to make sure that the io is the same then you'd have do e.g. something like this: Make a module that exports a promise of io and some way to initialize it - a function that gets the server and everything needed. Now, in the place where you have the server you can require the module and initialize it with that exported function, and in other places you can import the module and use a promise.

Instead of a promise you could use callbacks or even just a property on the exported object that could be initially undefined and gets defined when the socket.io is initialized but using a promise would probably be most simple solution to make sure that you're not using it while it's not ready yet.

You didn't mention in your question whether or not you use some framework and which one if any, but some of the frameworks like Hapi give you an easy way to share functionality like that. E.g. see:

  • https://hapijs.com/tutorials/plugins

If you use Hapi then you should use plugins. If other framework then search for a similar feature.



来源:https://stackoverflow.com/questions/43232300/require-the-same-instance-of-socket-io-in-multiple-modules

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!