【问题标题】:How to re-use Node.js module when required with different paths如何在需要不同路径时重用 Node.js 模块
【发布时间】:2018-02-15 18:47:04
【问题描述】:

我有一个名为 counter 的自定义模块,它被多个其他模块使用。这些其他模块位于不同的目录中,这导致需要具有不同路径的 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

如果使用相同的包含路径,则 counter 只会创建一次,并且 module1 和 module2 将使用相同的 counter 模块。但是因为 require 路径不同,所以创建了两个单独的 counter 模块。

有人知道如何防止这种情况吗?我希望只有一个 counter 模块。

【问题讨论】:

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

标签: node.js node-modules


【解决方案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

【讨论】:

    【解决方案2】:

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

    在主文件中-

    global.count=0;
    

    在 counter.js 中

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

    这样您就不需要更改您的 module1.js 和 module2.js,甚至对于更多的模块,您也可以像之前一样使用它。

    【讨论】:

      【解决方案3】:

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

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

      在主文件中

      global.counter = require('./counter');
      

      在模块文件中

      global.counter.increment();
      

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

      【讨论】:

        【解决方案4】:

        我在我的项目中使用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
        {}
        >
        

        . 表示当前文件夹。

        【讨论】:

          猜你喜欢
          • 2012-11-08
          • 1970-01-01
          • 2015-11-03
          • 2012-08-30
          • 1970-01-01
          • 1970-01-01
          • 2019-01-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多