繁体   English   中英

Node.js,Express和Dependency Injection

[英]Node.js, Express and Dependency Injection

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

我知道像Rewire这样的软件包的存在,但是现在我想尝试DI方法。 问题是, 如何实现均衡以保持轻量级的感觉,使得与节点一起使用经过良好测试的依赖注入应用程序的可靠性 (我知道经过充分测试的是给出了可靠性;-))。

节点模块

其中一个问题是,如何管理外部模块,如果某个对象需要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()来调用处理程序,因此上下文丢失,我们无法使用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实例。
  • 我也更愿意注入一切。 否则,时间将到来,当我想编写单元测试并且它变得困难,因为我有一个硬编码(未注入)依赖项,我无法模拟。

为了在使用节点时保持这种轻量级的感觉,您需要一种不会增加过多复杂性的依赖注入方法。 你上面的明确例子让我想起了Vojta Jina的一次演讲 ,其中他对依赖注入的布线部分提出了重要观点。 (观看分钟3:35到8:05)我无法解释它比Vojtja在他的演讲中做得更好但基本上他说我们需要一个di框架来处理布线(注入什么内容)。 否则,我们手动写入以设置接线的代码将无法维护。 每个单元测试也需要这样的接线代码。 IMO是手动依赖注入不再是一种选择的地方。

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

node.js有很多di框架 ,我想添加自己的框架“Fire Up!” 如果您使用它,您的示例将如下所示:

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很接近

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM