Javascript Node.js、Express和依赖项注入

Javascript Node.js、Express和依赖项注入,javascript,node.js,express,dependency-injection,Javascript,Node.js,Express,Dependency Injection,我正处于node.js项目的早期阶段,我希望改进整个应用程序组织。过去我使用Symfony2(PHP),现在我用Angular编写了很多代码,这两种语言都非常依赖DI。因此,我非常喜欢在node.js项目中应用相同的原则 我知道这样的包的存在,但现在我想尝试DI方法。问题是,如何实现平衡,以保持轻量级的感觉,即使用经过良好测试的依赖注入应用程序的稳定性来使用node(我知道经过良好测试的应用程序才具有稳定性;-) 节点模块 其中一个问题是如何管理外部模块,如果某个对象需要fs模块,该怎么办?正如

我正处于node.js项目的早期阶段,我希望改进整个应用程序组织。过去我使用Symfony2(PHP),现在我用Angular编写了很多代码,这两种语言都非常依赖DI。因此,我非常喜欢在node.js项目中应用相同的原则

我知道这样的包的存在,但现在我想尝试DI方法。问题是,如何实现平衡,以保持轻量级的感觉,即使用经过良好测试的依赖注入应用程序的稳定性来使用node(我知道经过良好测试的应用程序才具有稳定性;-)

节点模块 其中一个问题是如何管理外部模块,如果某个对象需要
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();
快车 由于Express使用
apply()
调用处理程序,因此上下文丢失,我们无法使用
。所以我们只剩下这些:

// 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框架的使用情况如何?(喜欢)和如何保持体验的精益?欢迎提出任何意见。谢谢

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

  • 拥有无状态模块将有助于横向扩展应用程序。如果所有状态都在一个数据库中,那么并行运行多个node.js实例就很容易了
  • 我也喜欢注入一切。否则,当我想要编写一个单元测试的时候,它会变得很难,因为我有一个硬编码的(不是注入的)依赖项,我不能模仿它
为了在使用节点时保持这种轻量级的感觉,您需要一种不会增加太多复杂性的依赖项注入方法。您上面的示例让我想起了一个例子,其中他对依赖注入的连接部分提出了一个重要的观点。(看第3:35到8:05分钟)我不能比Vojtja在他的演讲中解释得更好,但基本上他说我们需要一个di框架来处理布线(什么被注入到什么中)。否则,我们为设置接线而手动编写的代码将无法维护。此外,每个单元测试都需要这样的接线代码。在IMO中,手动依赖注入不再是一种选择

当您使用di框架(或许多人说的di容器)时,基本思想是每个单独的模块说明它需要哪些依赖项以及其他模块可以通过哪些id来要求它。然后可以调用di框架来初始化作为入口点的模块(例如app.js),框架将查找所有依赖项并接管注入适当模块实例的艰巨工作

我想添加我自己的例子:如果您使用它,您的示例将如下所示:

foo.js bar.js app.js index.js 运行
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的示例的感兴趣

希望有帮助

您可以查看


这与Symfony中的DIC很接近,有一个疑问,向控制器注入类似“异步”的东西是否有意义?或者仅仅要求它到位不是更方便吗?对于像“path”这样的模块也是一样的。在适当的地方尝试Require会挫败DI的目的,因为每次你想用另一个实现替换依赖项时,你都必须更新Require!如果你不介意的话,你可以更新你的答案来添加一个ES6版本的类吗
// Fire me up!

module.exports = {
    implements: 'bar',
    inject: ['require(fs)'],
    factory: function (fs) {
        return {
            index: function (req, res, next) {
                // fs...
            }
        };
    }
};
// 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);
};
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.
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)