【问题标题】:Require (the same instance of) socket.io in multiple modules在多个模块中需要(相同的)socket.io
【发布时间】:2017-08-31 03:12:18
【问题描述】:

我有点困惑,关于如何在 Node.js 中 require 和使用模块。

我的情况如下:

我在一个文件中编写了一个完整的服务器,它使用 Socket.io 进行实时通信。

现在 index.js 变得相当大了,我想将代码分成几个模块以使其更易于管理。

例如,我有一些功能可以向客户提供调查并获取他们的答案。我将所有这些函数放在一个单独的模块中,并在 index.js 中要求它。到目前为止工作正常。

我唯一关心的是,是否有另一种方法可以在模块内使用 SAME 套接字实例。

我当前的编码如下所示:

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;

这样可以正常工作,但我不乐意将 init 函数中的 io 传递给所需的模块。

这样做的“正确方法”是什么?

如果我在调查模块中require('socket.io'),它是否与index.js中的实例相同?

我什至如何要求它,因为它需要server,它需要app,它是在index.js 中创建的?

我很困惑,希望有人可以帮助我。谢谢!

【问题讨论】:

    标签: javascript node.js sockets module socket.io


    【解决方案1】:

    当您导入 node.JS 库时,您还可以传入对象。在您的情况下, index.js 文件应更改为以下内容:

    //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);
    

    然后只需更改您的survey.js 代码以获取io 对象:

    //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;
    };
    

    回答你的其他问题:

    如果您在调查模块中require('socket.io'),它将是与 index.js 不同的实例。

    编辑

    如果您想要一种更现代的方式...您可以使用 ES6 格式并创建一个类来更好地做到这一点:

    '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);
        };
    
    
    
    
    }
    

    【讨论】:

    • 如何以这种方式在调查模块中定义多个函数?目前的逻辑是var Survey = {}module.exports = Survey,因为我将许多函数附加到Survey
    • 这在我看来是有道理的。但是,我现在看到了多个示例,其中 - 而不是将 Survey 定义为匿名构造函数中的对象 - 该函数被命名,其他函数通过 Survey.prototype.loadSurvey = function(){} 附加。这似乎对我不起作用,我不知道为什么。 :( 示例:codinginthetrenches.com/2015/10/03/…
    【解决方案2】:

    当您在多个模块中执行此操作时:

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

    那么它将是所有需求的同一个对象。

    但如果你这样做:

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

    即使您在两个地方的server 中有相同的对象,io 也会是不同的值,因为它来自require('socket.io') 返回的函数的不同调用,即使这些函数是相同的。

    如果你想确保io 是相同的,那么你必须这样做,例如像这样:制作一个导出io 承诺的模块,并以某种方式对其进行初始化 - 一个获取server 的函数以及所需的一切。现在,在您拥有server 的地方,您可以要求模块并使用导出的函数对其进行初始化,而在其他地方您可以导入模块并使用promise。

    你可以使用回调,甚至只是导出对象上的一个属性,而不是一个承诺,它最初可能是未定义的,并在初始化 socket.io 时被定义,但使用承诺可能是确保你的最简单的解决方案'还没准备好就不用了。

    您没有在问题中提到您是否使用某个框架以及使用哪个框架(如果有的话),但是像 Hapi 这样的一些框架为您提供了一种共享此类功能的简单方法。例如。见:

    如果您使用 Hapi,那么您应该使用插件。如果是其他框架,则搜索类似的功能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-29
      • 2012-02-11
      • 1970-01-01
      • 2014-05-30
      • 1970-01-01
      • 2016-06-12
      相关资源
      最近更新 更多