Node.js,Express和dependency injection

我在一个node.js项目的早期阶段,我正在寻求改善整个应用程序的组织。 在过去,我使用了Symfony2(PHP),现在我在Angular中编写了很多代码,这两个代码都非常依赖DI。 所以,我非常喜欢在我的node.js项目中应用相同的原则。

我知道像Rewire这样的软件包的存在,但现在我想尝试DI方法。 问题是, 如何达到一个平衡,以保持轻量级的感觉,使节点与一个经过良好testing的dependency injection的应用程序的坚实 (我知道,经过充分testing是什么给了坚实;-))。

节点模块

其中一个问题就是如何pipe理外部模块,如果某个对象需要fs模块怎么办? 正如Vojta Jina(来自AngularJS)在这篇文章中所述 :

所以现在最适合我的方式就是这样的:模块是无状态的。 它们只包含类/函数/常量的定义。

所以,我想我必须注入一切:

 function Foo(fs) { this.fs = fs; } Foo.prototype.doSomething: function () { // this.fs... }; module.exports = Foo; 

某处:

 var fs = require('fs'); var Foo = require('./Foo'); var foo = new Foo(fs); foo.doSomething(); 

performance

由于Express使用apply()来调用处理程序,所以上下文丢失,我们不能使用this 。 所以我们留下这些:

 // foo.js function Foo(fs) { this.fs = fs; } Foo.prototype.index = function () { var self = this; return function (req, res, next) { // self.fs... }; }; module.exports = Foo; // bar.js module.exports.index = function (fs) { return function (req, res, next) { // fs... }; }; // app.js var express = require('express'); var fs = require('fs'); var app = express(); var Foo = require('./foo'); var foo = new Foo(fs); var bar = require('./bar'); app.get('/foo', foo.index()); app.get('/bar', bar.index(fs)); 

所以…

有人采取这种方法? 那么使用DI框架呢? (如di.js )以及如何保持经验的精益 ? 所有的想法都欢迎。 谢谢!

你有一些我想补充的好想法:

  • 拥有无状态模块将有助于您横向扩展您的应用程序。 如果所有状态都在数据库中,那么并行运行多个node.js实例将很容易。
  • 我也喜欢注入一切。 否则时间会来,当我想写一个unit testing,它变得很难,因为我有一个硬编码(不注入)的依赖我不能嘲笑。

为了在使用节点时保持这种轻量级的感觉,您需要一种dependency injection的方法,不会增加太多的复杂性。 上面的例子让我想起了Vojta Jina的谈话 ,他在这里谈到了dependency injection的布线部分。 (观看分钟3:35至8:05)Vojtja在谈话中不能说得更好,但基本上他说我们需要一个di框架来处理布线(注入什么)。 否则,我们手动编写的代码来设置布线将不可维护。 每个unit testing也需要这样的接线代码。 而IMO则是手动dependency injection不再是一个选项。

当你使用一个di框架(或许多人所说的di容器)时,其基本思想是每个单独的模块指出它需要哪个依赖关系,并且通过哪个id可以被其他模块需要。 然后,可以调用di框架来初始化作为入口点的模块(例如app.js),框架将查找所有依赖关系,并接pipe注入适当模块实例的工作。

node.js有很多di框架 ,我想添加自己的: “启动!” 如果你使用它,你的例子看起来像这样:

foo.js

 // Fire me up! function Foo(fs) { this.fs = fs; } Foo.prototype.index = function () { var self = this; return function (req, res, next) { // self.fs... }; }; module.exports = { implements: 'foo', inject: ['require(fs)'], _constructor: Foo }; 

bar.js

 // Fire me up! module.exports = { implements: 'bar', inject: ['require(fs)'], factory: function (fs) { return { index: function (req, res, next) { // fs... } }; } }; 

app.js

 // Fire me up! module.exports = { implements: 'app', inject: ['require(express)', 'foo', 'bar'] }; module.exports.factory = function (express, foo, bar) { var app = express(); app.get('/foo', foo.index()); app.get('/bar', bar.index); }; 

index.js

 var fireUpLib = require('fire-up'); var fireUp = fireUpLib.newInjector({ basePath: __dirname, modules: ['./lib/**/*.js'] // foo.js, bar.js, app.js are on this path }); fireUp('app'); // This is where the injection is kicked off. 

运行node index.js会得到以下输出:

 fireUp# INFO Requested: app, implemented in: lib/app.js fireUp# INFO |-- Requested: require(express) fireUp# INFO |-- Requested: foo, implemented in: lib/foo.js fireUp# INFO |-- Requested: require(fs) fireUp# INFO |-- Requested: bar, implemented in: lib/bar.js fireUp# INFO |-- Requested: require(fs) 

如果这看起来值得尝试,那么您可能会对“ 入门”部分感兴趣,该部分将展示基于Express的示例。

希望有所帮助!

你可以检查https://www.npmjs.com/package/plus.container

这在Symfony中接近DIC