在 Node.js 中将公共变量传递到单独模块的最佳方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10306185/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the best way to pass common variables into separate modules in Node.js?
提问by Serg
I use separate router files as modules for main app and auth app. I can't get the best way to pass variables(db client) into routers. I don't want to hardcode it or pass it with:
我使用单独的路由器文件作为主应用程序和身份验证应用程序的模块。我无法获得将变量(db 客户端)传递到路由器的最佳方法。我不想对其进行硬编码或通过以下方式传递它:
module.exports = function(app, db) {
Maybe it's best way to use singleton register or use global db variable?
也许这是使用单例寄存器或使用全局数据库变量的最佳方式?
What is your experiense with design-patterns? Which way is the best and why?
您在设计模式方面的经验是什么?哪种方式最好,为什么?
回答by Domenic
I have found using dependency injection, to pass things in, to be the best style. It would indeed look something like you have:
我发现使用依赖注入来传递东西是最好的风格。它确实看起来像你所拥有的:
// 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.
This has a number of benefits:
这有很多好处:
- It forces you to separate your system into components with clear dependencies, instead of hiding the dependencies somewhere in the middle of the file where they call
require("databaseSingleton")or worse,global.database. - It makes unit testing very easy: if I want to test
Routesin isolation, I can inject it with fakeappanddatabaseparams and test only theRoutescode itself. - It puts all your object-graph wiring together in a single place, namely the composition root (which in this case is
server.js, the app entry point). This gives you a single place to look to see how everything fits together in the system.
- 它迫使您将系统分成具有明确依赖关系的组件,而不是将依赖关系隐藏在它们调用的文件中间的某个地方,
require("databaseSingleton")或者更糟的是,global.database. - 它使单元测试变得非常容易:如果我想单独测试
Routes,我可以用 fakeapp和databaseparams注入它,然后只测试Routes代码本身。 - 它将所有对象图连接放在一个地方,即组合根(在这种情况下是
server.js应用程序入口点)。这为您提供了一个查看系统中所有内容如何组合在一起的单一位置。
One of the better explanations for this that I've seen is an interview with Mark Seeman, author of the excellent book Dependency Injection in .NET. It applies just as much to JavaScript, and especially to Node.js: requireis often used as a classic service locator, instead of just a module system.
我所看到的对此更好的解释之一是对 Mark Seeman 的采访,他是优秀书籍Dependency Injection in .NET 的作者。它同样适用于 JavaScript,尤其是 Node.js:require通常用作经典的服务定位器,而不仅仅是模块系统。
回答by akaravashkin
I suggest you create a settings file with db instance and with other things which you need use globally like 'singleton'.
我建议您使用 db 实例和其他需要全局使用的东西(如“单例”)创建一个设置文件。
For example, I have settings.js with my redis db client:
例如,我的 redis db 客户端有 settings.js:
var redis = require('redis');
exports.redis = redis.createClient(6379, '127.0.0.1');
And in other multiple modules I include it:
在其他多个模块中,我将其包含在内:
var settings = require('./settings');
setting.redis.<...>
Many time including it I always have one instance of db connection.
很多时候包括它我总是有一个数据库连接实例。
回答by gafi
You can save yourself all the boilerplate code of wiring up your modules if you use a dependency injection framework
如果您使用依赖注入框架,您可以保存所有连接模块的样板代码
This answerlists a few of them. I also built a simpler DI framework here.
这个答案列出了其中的一些。我还在这里构建了一个更简单的 DI 框架。
EDIT:below is a copy form the answer in case that page changes
编辑:下面是一个副本形式的答案,以防页面更改
requireis theway of managing dependencies in Node.js and surely it is intuitive and effective, but it has also its limitations.
require是Node.js 中管理依赖项的方式,当然它直观有效,但也有其局限性。
My advice is to take a look at some of the Dependency Injection containers available today for Node.js to have an idea on what are their pros/cons. Some of them are:
我的建议是查看一些目前可用于 Node.js 的依赖注入容器,以了解它们的优缺点。他们之中有一些是:
Just to name a few.
仅举几个。
Now the real question is, what can you achieve with a Node.js DI container, compared to a simple require?
现在真正的问题是,与简单的require.
Pros:
优点:
- better testability: modules accepts their dependencies as input
- Inversion of Control: decide how to wire your modules without touching the main code of your application.
- a customizable algorithm for resolving modules: dependencies have "virtual" identifiers, usually they are not bound to a path on the filesystem.
- Better extensibility: enabled by IoC and "virtual" identifiers.
- Other fancy stuff possible:
- Async initialization
- Module lifecycle management
- Extensibility of the DI container itself
- Can easily implement higher level abstractions (e.g. AOP)
- 更好的可测试性:模块接受它们的依赖作为输入
- 控制反转:决定如何在不触及应用程序主要代码的情况下连接模块。
- 用于解析模块的可定制算法:依赖项具有“虚拟”标识符,通常它们不绑定到文件系统上的路径。
- 更好的可扩展性:由 IoC 和“虚拟”标识符启用。
- 其他可能的花哨的东西:
- 异步初始化
- 模块生命周期管理
- DI 容器本身的可扩展性
- 可以轻松实现更高级别的抽象(例如 AOP)
Cons:
缺点:
- Different from the Node.js "experience": not using
requiredefinitely feels like you are deviating from the Node way of thinking. - The relationship between a dependency and its implementation is not always explicit. A dependency may be resolved at runtime and influenced by various parameters. The code becomes more difficult to understand and debug
- Slower startup time
- Maturity (at the moment): none of the current solutions is reallypopular at the moment, so not so many tutorials, no ecosystem, not battle tested.
- Some DI containers will not play well with module bundlers like Browserify and Webpack.
- 与Node.js的“体验”不同:不使用
require肯定感觉是在偏离Node的思维方式。 - 依赖项与其实现之间的关系并不总是明确的。依赖关系可以在运行时解决并受各种参数的影响。代码变得更难理解和调试
- 启动时间较慢
- 成熟度(目前):目前没有一个解决方案是真正流行的,所以没有那么多教程,没有生态系统,也没有经过实战测试。
- 某些 DI 容器与 Browserify 和 Webpack 等模块捆绑器不能很好地配合使用。
回答by Vinz243
It is completely outdated, but you can use globalin a script :
它已经完全过时了,但您可以global在脚本中使用:
global.foo = new Foo();
in another script :
在另一个脚本中:
foo.bar();
You can also use already existing constant :
您还可以使用已经存在的常量:
Object.foo = new Foo();
And here :
和这里 :
Object.foo.bar();

