在Node.js中不绑定配置到全局对象的任何理由

Any reason not to bind configurations to global object in Node.js?

本文关键字:对象 全局 任何 理由 配置 js Node 绑定      更新时间:2023-09-26

我正在寻找在我的Node应用程序中使用全局配置设置的最佳方法。按照我的喜好,我找到的方法有:

  1. 将配置附加到全局对象

    global.config = {
        db: require('./config/db'),
        server: require('./config/server'),
        session: require('./config/session'),
        auth: require('./config/auth')
    };
    
  2. 将配置对象传递给需要它的模块。

    var config = {
        db: require('./config/db'),
        server: require('./config/server'),
        session: require('./config/session'),
        auth: require('./config/auth')
    };
    var responder = require('./responder')(config);
    
  3. 每个模块都需要配置文件。因为我通常把我的配置分割成单独的文件,我真的不喜欢这样做。因为我不总是使用某些文件,所以通常也需要检查文件是否存在。

有什么理由应该避免这两种方法吗?有什么理由让一个人比其他人更受欢迎吗?

根据我的经验,使用选项No是一种常见的做法和良好的风格。2:将配置选项传递给需要它的模块

:

  • 它将配置与实际逻辑解耦。如果将配置文件包含在对于模块本身,有一个不必要的依赖于一个特定的配置文件。
  • 仍然有一个定义的依赖于作为参数提供的特定配置值-而不是"神奇地"从全局命名空间中提取,这使得代码难以阅读,维护和测试。
这是一个经验法则,几乎每一种语言都允许全局变量/对象和结构,包括"你喜欢的一切,你喜欢的任何地方"。但是requirejs已经把你推向了一个正确的方向至少允许exports是一个可以立即接受构型的函数。因此,一行代码是要求和配置资源的一种优雅方式。

除此之外的一切都可能以依赖注入(DI)概念的讨论告终——这是一个单独的主题。

对于小型项目,这三种方法都是可以接受的。对于大的,我可以说下一个:

全局变量是个问题

如果你开始使用这种方式,你需要保护像var config = {...}; config.freeze();这样的配置对象。在任何情况下,全局变量都是一个不好的做法,特别是对于NodeJS,因为它破坏了模块化系统。

传递配置是最好的方法

那是原因吗?测试

在测试中,你需要获取配置文件的一些状态。第一种和第三种方法提供了下一个代码样式:

config.js

module.exports= {
  a: 10
};

app.js

var config = require('config');
module.exports.func = function(){
  if (config.a > 10) return 'A';
  return 'B';
}

摩卡+茶测试

var expect = require('chai').except,
    config = require('config'),
    app = require('app');
describe('Func', function(){
  it('return "A" if a > 10', function(){
    config.a = 12; //DHOOO!!! (c) Homer Simpson
    expect(app.func()).to.equal('A');
  });
  it('return "B" if a <= 10', function(){
    config.a = 9;
    expect(app.func()).to.equal('B');
  });
  config.a = 12; //return default state of config. DHOOO!!!
});

你怎么能看到你需要有可编辑的配置,这是一个不好的做法(大项目,每个开发人员可以在任何地方改变配置状态…DHOOO ! !)

第二种方式是这样的:

config.js

var config = {
  a: 10
};
config.freezy();
module.exports = config;

app.js

module.exports.func = function(config){
  if (config.a > 10) return 'A';
  return 'B';
}

摩卡+茶测试

var expect = require('chai').except,
    app = require('app');
describe('Func', function(){
  it('return "A" if a > 10', function(){
    expect(app.func({a:12})).to.equal('A');
  });
  it('return "B" if a <= 10', function(){
    expect(app.func({a:9})).to.equal('B');
  });
});

更新

在这个例子中,func是非常综合的,对于实际项目,您可以看到这样的东西:

module.js

var SubModule = require('submodule');
function MyModule(config, someVar) {
 //Don't use full config, only options you needed.
 //Pull out config options
  this._a = config.a;
  this._b = config.b;
  this.doSomethink(someVar);
  this.subModule = new SubModule(config);
}
MyModule.prototype.doSomething = function(){
  if (this._a > 10) return 'A';
  return 'B';
}
module.exports = MyModule;`

submodule.js

function MySubModule(config) {
  this._c = config.c;
}
module.exports = MySubModule;