有什么理由不将配置绑定到Node.js中的全局对象?

时间:2014-05-13 09:42:34

标签: javascript node.js configuration

我正在寻找在我的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. 要求每个模块中的配置文件。由于我通常将配置分成单独的文件,所以我真的不喜欢这样做。由于我不总是使用某些文件,因此通常也会检查文件是否存在。

  4. 有什么理由可以避免这些方法中的任何一种吗?有没有理由为什么一个人应该优先于其他人呢?

2 个答案:

答案 0 :(得分:1)

根据我的经验,使用选项 No是常用和好的风格。 2:将配置选项传递给需要它的模块你建议。

<强>原因

  • 它将配置与实际逻辑分离。如果您包含配置文件 模块本身对一个特定配置文件有不必要的依赖。
  • 对于作为参数提供的特定配置值仍然存在定义的依赖关系 - 而不是从全局命名空间中“神奇地”拉出,这使得代码难以阅读,维护和测试。

这是几乎每种语言的经验法则,它允许诸如全局变量/对象和构造之类的东西,包括“你喜欢的任何地方”。但是requirejs已经通过至少允许exports成为立即接受配置的函数而向您推进了正确的方向。因此,单线程是一种需要和配置资源的优雅方式。

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

答案 1 :(得分:0)

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

全局变量是一个问题

如果您开始使用这种方式,则需要保护配置对象,如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';
}

Mocha + Chai测试

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

Mocha + Chai测试

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;