将公共变量传递到Node.js中的单独模块的最佳方法是什么?

时间:2012-04-24 21:21:52

标签: design-patterns node.js

我使用单独的路由器文件作为主应用和auth app的模块。我无法获得将变量(db client)传递到路由器的最佳方法。我不想硬编码或传递它:

module.exports = function(app, db) {

也许这是使用单例寄存器或使用全局db变量的最佳方法?

您对设计模式的体验是什么?哪种方式最好,为什么?

4 个答案:

答案 0 :(得分:108)

我发现使用依赖注入来传递信息是最好的风格。它确实看起来像你有:

// App.js
module.exports = function App() {
};

// Database.js
module.exports = function Database(configuration) {
};

// Routes.js
module.exports = function Routes(app, database) {
};

// server.js: composition root
var App = require("./App");
var Database = require("./Database");
var Routes = require("./Routes");
var dbConfig = require("./dbconfig.json");

var app = new App();
var database = new Database(dbConfig);
var routes = new Routes(app, database);

// Use routes.

这有很多好处:

  • 它会强制您将系统分离为具有明确依赖关系的组件,而不是将依赖关系隐藏在文件中间的某个位置({1}}或更糟,require("databaseSingleton")
  • 它使单元测试变得非常简单:如果我想单独测试global.database,我可以使用假Routesapp参数注入它并仅测试database代码本身。
  • 它将所有对象图连接放在一个位置,即组合根(在本例中为Routes,即应用程序入口点)。这为您提供了一个查看系统中所有内容如何组合的地方。

我见过的对此更好的解释之一是an interview with Mark Seeman,优秀着作 .NET中的依赖注入的作者。它同样适用于JavaScript,尤其适用于Node.js:server.js通常用作经典服务定位器,而不仅仅是模块系统。

答案 1 :(得分:2)

我建议你创建一个包含db实例的设置文件,以及你需要全局使用的其他东西,比如'singleton'。

例如,我在我的redis数据库客户端上有settings.js:

var redis = require('redis');
exports.redis = redis.createClient(6379, '127.0.0.1');

在其他多个模块中,我包括它:

var settings = require('./settings');
setting.redis.<...>

很多时候包括它我总是有一个数据库连接实例。

答案 2 :(得分:1)

如果您使用依赖注入框架

,您可以自己保存所有连接模块的样板代码

This answer列出了其中一些。我还构建了一个simpler DI framework here

编辑:以下是该页面更改时的答案副本

require 在Node.js中管理依赖关系的方式,当然它是直观有效的,但它也有其局限性。

我的建议是看看今天可用于Node.js的一些依赖注入容器,以了解它们的优缺点。其中一些是:

仅举几例。

现在真正的问题是,与简单的require相比,使用Node.js DI容器可以实现什么?

<强>优点:

  • 更好的可测试性:模块接受其依赖项作为输入
  • 控制反转:决定如何在不触及应用程序主代码的情况下连接模块。
  • 用于解析模块的可定制算法:依赖关系具有&#34;虚拟&#34;标识符,通常它们不绑定到文件系统上的路径。
  • 更好的可扩展性:由IoC和&#34;虚拟&#34;标识符。
  • 其他可能的花哨的东西:
    • 异步初始化
    • 模块生命周期管理
    • DI容器本身的可扩展性
    • 可以轻松实现更高级别的抽象(例如AOP)

<强>缺点:

  • 不同于Node.js&#34;体验&#34;:不使用require绝对感觉你偏离了Node的思维方式。
  • 依赖项与其实现之间的关系并不总是明确的。可以在运行时解决依赖性并且受各种参数的影响。代码变得更难理解和调试
  • 启动时间较慢
  • 成熟度(目前):目前没有一种解决方案非常受欢迎,所以没有那么多教程,没有生态系统,没有经过战斗测试。
  • 某些DI容器无法与Browserify和Webpack等模块捆绑器配合使用。

答案 3 :(得分:0)

它已完全过时,但您可以使用global 在脚本中:

 global.foo = new Foo();

在另一个脚本中:

 foo.bar();

您还可以使用已存在的常量:

 Object.foo = new Foo();

在这里:

 Object.foo.bar();