如何在需要时使用不同的路径重用Node.js模块

时间:2018-02-15 08:50:19

标签: node.js node-modules

我有一个名为 counter 的自定义模块,由多个其他模块使用。这些其他模块位于不同的目录中,这导致计数器模块需要不同的路径。

以下是简化设置。

- dir1
-- counter.js
-- module1.js
- dir2
-- module2.js

counter.js

var count = 0;

counter.increment = function(){
  count++;
  console.log(count);
};

module1.js

var counter = require('./counter');
counter.increment(); // Prints 1

module2.js

var counter = require('../dir1/counter')
counter.increment(); // Prints 1, but should print 2

如果使用相同的包含路径,则计数器只会创建一次,并且module1和module2将使用相同的计数器模块。但由于需求路径不同,因此会创建两个单独的计数器模块。

有谁知道如何防止这种情况?我想只有一个计数器模块。

4 个答案:

答案 0 :(得分:1)

由于你想要一个每个应用程序的单例并且require()无法知道具有两个独立路径的模块实际上是同一个模块,所以我知道这样做的唯一方法(除了删除单独的模块的路径是让你的模块将一个单例注册为全局,然后在创建另一个单例之前让它自己对该单例进行初始化检查。然后,每次加载它时,它只返回一个指向那个单例的导出。

 // counter.js
 // if no singleton yet, create the one singleton
 if (!global._counter) {
    global._counter = new Counter();
 }
 // export the singleton
 module.exports = global._counter;

第一次加载require()(无论路径是什么),它将创建一个单例并将其存储在global._counter变量中。第二次加载(即使使用不同的路径),它将找到前一个单例并只导出相同的单例。所以,只会有一个柜台。

这使得使用它的所有代码都像真实模块一样对待它,并避免在此处使用global引用。通常要避免使用全局变量,但是当你想要单例引用某个东西并且不能使用模块级变量来保存它时,这是一件好事(这是你的确切情况)。

然后,您可以像普通模块一样使用它:

var counter = require('./counter');
counter.increment(); // Prints 1

// in another file
var counter = require('../dir1/counter');
counter.increment(); // Prints 2

答案 1 :(得分:1)

一个好的解决方案是只将count变量设为全局而不是使整个模块全局化。例如 -

在主文件中 -

aws lambda add-permission --function-name X --source-arn "X" --principal apigateway.amazonaws.com --statement-id X --action lambda:InvokeFunction

在counter.js

var connString = "Host=myserver;Username=mylogin;Password=mypass;Database=mydatabase";

using (var conn = new NpgsqlConnection(connString))
{
    conn.Open();

    // Insert some data
    using (var cmd = new NpgsqlCommand())
    {
        cmd.Connection = conn;
        cmd.CommandText = "INSERT INTO data (some_field) VALUES (@p)";
        cmd.Parameters.AddWithValue("p", "Hello world");
        cmd.ExecuteNonQuery();
    }

    // Retrieve all rows
    using (var cmd = new NpgsqlCommand("SELECT some_field FROM data", conn))
    using (var reader = cmd.ExecuteReader())
        while (reader.Read())
            Console.WriteLine(reader.GetString(0));
}

通过这种方式,您无需更改module1.js和module2.js,甚至可以使用其他模块,也可以像以前一样使用它。

答案 2 :(得分:0)

这是因为当你导入一个文件时,它会在那里创建一个新的实例,所以在你的每个模块中它都会从0开始。

解决方案是将计数器作为全局导入主文件并在任何地方使用

主文件中的

global.counter = require('./counter');
模块文件中的

global.counter.increment();

计数器文件可以从任何文件,模块加载,它不重要。只需声明一次并确保在使用增量方法之前加载它。

答案 3 :(得分:0)

我在项目中使用NODE_PATH环境变量。它的价值在于项目的根源。然后需要本地模块就像需要npm模块一样。

对于相同的设置,我更改了require语句:

以下是简化设置。

- dir1
-- counter.js
-- module1.js
- dir2
-- module2.js

counter.js

var count = 0;

exports.increment = function(){
  count++;
  console.log(count);
};

module1.js

var counter = require('dir1/counter');
counter.increment(); // Prints 1

module2.js

var counter = require('dir1/counter')
counter.increment(); // Prints 2

我使用NODE_ENV环境变量运行程序。

NODE_ENV=. node
> require('dir1/module1');
1
{}
> require('dir2/module2');
2
{}
>

.表示当前文件夹。