我需要在NodeJS中进行依赖注入,还是要处理……?

我目前使用nodejs创建一些实验项目。我已经用Spring编写了很多Java EE Web应用程序,并赞赏那里的依赖注入的简易性。

现在我很好奇:如何使用节点进行依赖注入?或者:我什至需要它吗?是否存在替代概念,因为编程风格不同?

到目前为止,我在谈论简单的事情,例如共享数据库连接对象,但是我还没有找到一个令我满意的解决方案。

猿泡芙2020/03/23 14:18:11

我认为其他职位在使用DI的论点上做得很好。对我来说,原因是

  1. 在不知道其路径的情况下注入依赖项。这意味着,如果您更改磁盘上的模块位置或与另一个模块交换位置,则无需触摸依赖该模块的每个文件。

  2. 它使模拟测试依赖关系变得容易得多,而无需以require没有问题的方式重写全局函数的痛苦

  3. 它可以帮助您将应用程序组织和推理为松散耦合的模块。

但是我很难找到一个我和我的团队可以轻松采用的DI框架。所以我最近基于这些功能构建了一个名为deppie的框架

  • 几分钟即可掌握的最小API
  • 无需额外的代码/配置/注释
  • 一对一直接映射到require模块
  • 可以部分采用以与现有代码一起使用
卡卡西Near2020/03/23 14:18:11

Node.js requires DI as much as any other platform. If you are building something big, DI will make it easier to mock the dependencies of your code and test your code thoroughly.

Your database layer modules for example, shouldn’t just get required at your business code modules because, when unit testing these business code modules, the daos will load and connect to the database.

One solution would be to pass the dependencies as module parameters:

module.exports = function (dep1, dep2) {
// private methods

   return {
    // public methods
       test: function(){...}
   }
}

这样,可以轻松自然地模拟依赖关系,并且您可以专注于测试代码,而无需使用任何棘手的第三方库。

还有其他解决方案(百老汇,建筑师等)可以为您提供帮助。尽管他们可能做的比您想要的更多,或使用起来更混乱。

十三Harry2020/03/23 14:18:11

TypeDI是这里提到的最甜的,请在TypeDI中查看此代码

import "reflect-metadata";
import {Service, Container} from "typedi";

@Service()
class SomeClass {

    someMethod() {
    }

}

let someClass = Container.get(SomeClass);
someClass.someMethod();

看看下面的代码:

import {Container, Service, Inject} from "typedi";

// somewhere in your global app parameters
Container.set("authorization-token", "RVT9rVjSVN");

@Service()
class UserRepository {

    @Inject("authorization-token")
    authorizationToken: string;

}
GO2020/03/23 14:18:10

Google的di.js可在Node.js(+浏览器)(+ ES6)上运行

宝儿2020/03/23 14:18:10

我长期使用.Net,PHP和Java,因此我也想在NodeJS中使用方便的依赖注入。人们说,NodeJS中的内置DI足够了,因为我们可以通过Module获得它。但这并不令我满意。我想保留一个模块不超过一个类。另外,我希望DI完全支持模块生命周期管理(单模块,瞬态模块等),但是对于Node模块,我不得不经常编写手动代码。最后,我想简化单元测试。这就是为什么我为自己创建了一个依赖注入。

如果您正在寻找DI,请尝试一下。可以在这里找到:https : //github.com/robo-creative/nodejs-robo-container完全记录在案。它还解决了DI的一些常见问题以及如何以OOP方式解决它们。希望能帮助到你。

村村2020/03/23 14:18:10

这取决于您的应用程序的设计。显然,您可以执行类似Java的注入操作,在其中创建类的对象,并在构造函数中传递这样的依赖关系。

function Cache(store) {
   this._store = store;
}

var cache = new Cache(mysqlStore);

如果您不使用JavaScript进行OOP,则可以创建一个初始化函数来设置所有内容。

但是,您可以采用另一种方法,这种方法在基于事件的系统(例如node.js)中更为常见。如果您可以对应用程序建模(仅在大多数情况下)仅对事件起作用,那么您所需要做的就是设置一切(我通常通过调用init函数来完成)并从存根发出事件。这使得测试相当容易且可读。

凯西里2020/03/23 14:18:10

了解下垂(Node.js的一个简单但功能强大的依赖项注入和实体(文件)管理框架)

https://github.com/devcrust/node-dips

Mandy2020/03/23 14:18:10

我认为我们仍然需要在Node.js中进行依赖注入,因为它可以放宽服务之间的依赖关系,并使应用程序更清晰。

受到Spring Framework的启发,我还实现了自己的模块以支持Node.js中的依赖注入。我的模块还能够检测code changesauto reload服务,而无需重新启动应用程序。

请访问我的项目:Buncha-IoC容器

谢谢!

伽罗2020/03/23 14:18:10

The reality is that you can test your node.js without IoC container because JavaScript is a really dynamic programming language and you can modify almost everything at run-time.

Consider the following:

import UserRepository from "./dal/user_repository";

class UserController {
    constructor() {
        this._repository = new UserRepository();
    }
    getUsers() {
        this._repository.getAll();
    }
}

export default UserController;

So you can override the coupling between components at run-time. I like to think that we should aim to decouple our JavaScript modules.

The only way to achieve real decoupling is by removing the reference to the UserRepository:

class UserController {
    constructor(userRepository) {
        this._repository = userRepository;
    }
    getUsers() {
        this._repository.getAll();
    }
}

export default UserController;

This means that somewhere else you will need to do the object composition:

import UserRepository from "./dal/user_repository";
import UserController from "./dal/user_controller";

export default new UserController(new UserRepository());

I like the idea of delegating the object composition to an IoC container. You can learn more about this idea in the article The current state of dependency inversion in JavaScript. The article tries to debunk some "JavaScript IoC container myths":

Myth 1: There is no place for IoC containers in JavaScript

Myth 2: We don’t need IoC containers, we already have module loaders!

Myth 3: Dependency inversion === injecting dependencies

If you also like the idea of using an IoC container you could take a look to InversifyJS. The latest release (2.0.0) supports many use cases:

  • Kernel modules
  • Kernel middleware
  • Use classes, string literals or Symbols as dependency identifiers
  • Injection of constant values
  • Injection of class constructors
  • Injection of factories
  • Auto factory
  • Injection of providers (async factory)
  • 激活处理程序(用于注入代理)
  • 多次注射
  • 标记绑定
  • 自定义标签 decorator
  • 命名绑定
  • 上下文绑定
  • 友好的异常(例如循环依赖)

您可以在InversifyJS上了解更多有关它的信息

小小2020/03/23 14:18:10

require在Node.js中管理依赖项方法,它肯定是直观且有效的,但也有其局限性。

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

仅举几个。

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

优点:

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

缺点:

  • 与Node.js的“体验”不同:require绝对不使用就好像您偏离了Node的思维方式。
  • 依赖关系及其实现之间的关系并不总是很明确。依赖关系可以在运行时解决,并受各种参数影响。代码变得更加难以理解和调试
  • 启动时间更短
  • Maturity (at the moment): none of the current solutions is really popular 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.

As with anything related to software development, choosing between DI or require depends on your requirements, your system complexity, and your programming style.

老丝阿飞2020/03/23 14:18:10

我还编写了一个模块来完成此任务,称为rewire只需使用npm install rewire,然后:

var rewire = require("rewire"),
    myModule = rewire("./path/to/myModule.js"); // exactly like require()

// Your module will now export a special setter and getter for private variables.
myModule.__set__("myPrivateVar", 123);
myModule.__get__("myPrivateVar"); // = 123


// This allows you to mock almost everything within the module e.g. the fs-module.
// Just pass the variable name as first parameter and your mock as second.
myModule.__set__("fs", {
    readFile: function (path, encoding, cb) {
        cb(null, "Success!");
    }
});
myModule.readSomethingFromFileSystem(function (err, data) {
    console.log(data); // = Success!
});

我受到Nathan MacInnes的注射器的启发,但使用了不同的方法。我不用vm来评估测试模块,实际上我使用节点自己的需求。这样,您的模块的行为就像使用一样require()(除了您的修改)。此外,还完全支持调试。