Node.js 中对象复用的做法

Node.js 中对象复用的做法

我是Java的背景,初入node,对对象复用不是很清楚。

比如,我现在的controller到了两不同的js文件中,文件中都需要用redis的client,我应该怎么处理? **Solution A: **

file1.js:

var redis = require(‘redis’).createClient();

file2.js

var redis = require('redis').createClient();

Solution B: redis.js

var redis = require('redis').createClient(); 

module.exports = redis;

file1.js

var redis = require('./redis'); 

file2.js

var redis = require(’./redis’);

================ 另外我也用到了socket.io,获取io对象采用 var app = require(‘express’)() , server = require(‘http’).createServer(app) , io = require(‘socket.io’).listen(server); 情况也一样,如果我要在两个文件中使用socket.io,难道我要用上面的代码两次么?如果是用两次,那么相当于要创建两个server对象?

请教一个最佳的实战方法。


5 回复

当然可以!在 Node.js 中实现对象复用是一个非常重要的实践,特别是在处理像 Redis 和 Socket.io 这样的模块时。以下是针对你提出的问题的解决方案。

对象复用的最佳实践

使用单例模式来复用 Redis 客户端

问题描述: 在多个文件中需要复用同一个 Redis 客户端实例。

解决方案:

  1. 创建一个单独的 Redis 模块

    // redis.js
    const redis = require('redis');
    
    let client;
    
    function getRedisClient() {
      if (!client) {
        client = redis.createClient();
      }
      return client;
    }
    
    module.exports = getRedisClient;
    
  2. 在其他文件中引入并使用该 Redis 客户端

    // file1.js
    const getRedisClient = require('./redis');
    
    const redisClient = getRedisClient();
    redisClient.set('key', 'value', (err, reply) => {
      console.log(reply); // OK
    });
    
    // file2.js
    const getRedisClient = require('./redis');
    
    const redisClient = getRedisClient();
    redisClient.get('key', (err, reply) => {
      console.log(reply); // value
    });
    

使用单例模式来复用 Socket.io 实例

问题描述: 在多个文件中需要复用同一个 Socket.io 实例。

解决方案:

  1. 创建一个单独的 Socket.io 模块

    // socket.js
    const express = require('express');
    const http = require('http');
    const socketIo = require('socket.io');
    
    let io;
    
    function getSocketIOInstance(app) {
      if (!io) {
        const server = http.createServer(app);
        io = socketIo.listen(server);
      }
      return io;
    }
    
    module.exports = getSocketIOInstance;
    
  2. 在其他文件中引入并使用该 Socket.io 实例

    // app.js
    const express = require('express');
    const getSocketIOInstance = require('./socket');
    
    const app = express();
    
    const io = getSocketIOInstance(app);
    
    io.on('connection', (socket) => {
      console.log('A user connected');
    });
    
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });
    
    // anotherFile.js
    const getSocketIOInstance = require('./socket');
    const app = require('./app');
    
    const io = getSocketIOInstance(app);
    
    io.on('connection', (socket) => {
      console.log('Another user connected');
    });
    

通过这种方式,你可以确保在多个文件中复用相同的 Redis 客户端和 Socket.io 实例,避免了重复创建和销毁资源,提高了应用的性能和效率。


如果你说的对象复用是指在不同模块之间访问同一个对象,那我可以理解为,你需要解决的是模块间的互访。

懒人的方式:使用全局对象 global

file1.js var redis_client = global.redis_client = require(‘redis’).createClient();

纠结但据说更优雅的方式:使用 exports 导出每个模块需要对外的接口

file1.js exports.redis_client = require(‘redis’).createClient();

file2.js var redis_client = require(’./file1.js’).redis_client;

module loading 只发生一次。node 在加载一个module的时候会查是不是已经加载了。

var app = require(‘express’)() , server = require(‘http’).createServer(app) , io = require(‘socket.io’).listen(server);

比如这段代码,如果我在两个文件中都有这段代码,意思是我得到的io是同一个实例?

在Node.js中,对象复用是一个重要的概念,以避免重复创建资源,从而提高性能。针对你的问题,我们可以通过模块化的方式将Redis客户端和Socket.IO实例作为单例对象进行管理。

示例代码

redis.js

// 创建一个Redis客户端并导出
let redisClient;

function getRedisClient() {
    if (!redisClient) {
        redisClient = require('redis').createClient();
    }
    return redisClient;
}

module.exports = getRedisClient;

file1.js 和 file2.js

const getRedisClient = require('./redis');

// 在需要使用Redis的地方调用getRedisClient
const redisClient = getRedisClient();

// 使用redisClient进行操作
redisClient.set('key', 'value', (err, reply) => {
    console.log(reply);
});

socket.io.js

// 创建一个Socket.IO实例并导出
let ioInstance;

function getIOInstance(app) {
    if (!ioInstance) {
        const server = require('http').createServer(app);
        ioInstance = require('socket.io')(server);
    }
    return ioInstance;
}

module.exports = getIOInstance;

app.js

const express = require('express');
const getIOInstance = require('./socket.io');

const app = express();
const io = getIOInstance(app);

io.on('connection', socket => {
    console.log('A user connected');
});

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});

解释

  1. Redis客户端

    • 我们通过getRedisClient函数确保Redis客户端只被创建一次,并且可以被多个文件共享。
  2. Socket.IO实例

    • 同样的,我们通过getIOInstance函数确保Socket.IO实例只被创建一次,并且可以在多个文件中共享。

这种方式不仅可以避免重复创建资源,还可以更好地管理和维护这些资源,提高代码的可读性和可维护性。

回到顶部