Javascript 如何在Nodejs中进行有效的依赖注入?

Javascript 如何在Nodejs中进行有效的依赖注入?,javascript,node.js,dependency-injection,Javascript,Node.js,Dependency Injection,让我们从一些参考代码开始 var express = require('express'); var app = express(); var session = require('express-session'); app.use(session({ store: require('connect-session-knex')() })); 如果你知道答案,我想回答几个问题: 每次在Nodejs中调用一个require,这就是所谓的依赖注入吗?或者依赖注入的真正含义是什么

让我们从一些参考代码开始

var express = require('express');  
var app = express();  
var session = require('express-session');

app.use(session({  
  store: require('connect-session-knex')()
}));
如果你知道答案,我想回答几个问题:

每次在Nodejs中调用一个
require
,这就是所谓的依赖注入吗?或者依赖注入的真正含义是什么

我之所以问这个问题,是因为我一直在阅读有关Node的文章,我看到人们在谈论
模块
模块。导出
模式,我很困惑,
模块
依赖关系
相同


所以,我所需要的只是一个关于依赖注入的清晰解释,以及何时/何地需要注入依赖

依赖注入在某种程度上与普通模块设计相反。在普通模块设计中,模块使用
require()
加载它所需的所有其他模块,目的是使调用者使用您的模块变得简单。调用者只需在您的模块中
require()
,您的模块将加载它所需的所有其他内容

使用依赖注入,而不是模块加载它需要的东西,调用方需要传入模块需要的东西(通常是对象)。这可以使某些类型的测试更容易,也可以使为测试目的模拟某些东西更容易

每次在Nodejs中调用require时,是否命名为dependency 注射?或者依赖注入的真正含义是什么

否。当模块执行
请求()
加载其自身的依赖项时,该依赖项不是依赖项注入

我之所以问这个问题,是因为我一直在读关于 节点,我看到人们在谈论模块或 module.export模式,我很困惑,该模块与 依赖

模块与依赖项不同。正常的模块设计允许您
require()。模块本身处理其自身依赖项的加载(通常使用模块内部的
require()

这里有几篇文章讨论了使用依赖注入的一些优缺点。据我所知,主要的优点是通过允许更容易地模拟依赖对象(如数据库)来简化单元测试


使用依赖项注入的典型情况是模块依赖于数据库接口。如果模块加载它自己的数据库,那么该模块本质上是硬连接到该特定数据库的。模块中没有内置体系结构供调用方指定应使用的存储类型

但是,如果模块的设置使调用方在加载和初始化模块时,必须传入实现特定数据库API的对象,则调用方可以自由决定应使用何种类型的数据库。任何符合API合同的数据库都可以使用。但是,调用者的负担是选择和加载特定的数据库。也可能存在混合情况,其中模块有一个默认使用的内置数据库,但调用方可以提供自己的对象,如果在模块构造函数或模块初始化中提供了该对象,则可以使用该对象。

想象一下这段代码

var someModule = require('pathToSomeModule');

someModule();
在这里,我们不依赖于名称,而是依赖于该文件的路径。我们每次也使用相同的文件

让我们看看angular的方式(我知道,对于客户,请容忍我)

我知道客户端js没有文件导入/导出,但这是您应该了解的基本概念。这个控制器没有指定$scope变量实际上是什么,它只知道angular给了它一个叫做$scope的东西

这是控制反转 这就像说,不要打电话给我,我会打电话给你

现在让我们用服务容器之类的东西来实现我们的原始代码(有许多不同的解决方案,容器不是唯一的选项)

我们在这里完成了什么?现在,我们只需要知道一件事,容器(或您选择的任何抽象)。我们不知道someModule实际上是什么,也不知道它的源文件在哪里,只知道它是我们从容器中得到的。这样做的好处是,如果我们想使用不同的
someModule
实现,只要它符合与原始版本相同的API,我们就可以在整个应用程序中替换一个位置。集装箱。现在,调用
someModule
的每个模块都将获得新的实现。其思想是,当您创建一个模块时,您可以定义用于与之交互的api。如果不同的实现都符合一个api(或者你编写了一个符合它的适配器),那么你可以替换掉像脏内衣这样的实现,你的应用程序就可以正常工作了

这种方法并不适用于所有人,有些人讨厌拖着沉重的行李在集装箱周围走

我个人的观点是,我宁愿编写接口代码(实现之间的一致api),也不愿编写具体实现的代码

node.js中依赖项注入的实际示例

// In a file, far, far, away
module.exports = function(dependencyA, dependencyB) {
  dependencyA();
  dependencyB();
}

// In another file, the `caller`
// This is where the actual, concrete implementation is stored
var depA = someConcreteImplementation;
var depB = someOtherConcreteImplementation;

var someModule = require('pathToSomeModule');

someModule(depA, depB);
这样做的缺点是,现在调用者需要知道您的依赖项是什么。一些人对此感到安慰,也喜欢它,其他人认为这是一个麻烦

我个人更喜欢下一种方法

如果您没有使用babel或在幕后更改函数的东西,那么可以使用这种方法来获取angular style参数

然后,您可以解析从
require
获得的函数,而不使用任何容器。

我使用的是:

npm i-p注入js

它是基于注射的,所以注射非常简单

这是自述文件中的typescript版本

import 'reflect-metadata';
import { ReflectiveInjector, Injectable, Injector } from 'injection-js';

class Http {}

@Injectable()
class Service {
  constructor(private http: Http) {}
}

@Injectable()
class Service2 {
  constructor(private injector: Injector) {}

  getService(): void {
    console.log(this.injector.get(Service) instanceof Service);
  }

  createChildInjector(): void {
    const childInjector = ReflectiveInjector.resolveAndCreate([
      Service
    ], this.injector);
  }
}

const injector = ReflectiveInjector.resolveAndCreate([
  Service,
  Http
]);

console.log(injector.get(Service) instanceof Service);

@azium实际上我只是读了它,但我没有得到我所需要的回应
// In a file, far, far, away
module.exports = function(dependencyA, dependencyB) {
  dependencyA();
  dependencyB();
}

// In another file, the `caller`
// This is where the actual, concrete implementation is stored
var depA = someConcreteImplementation;
var depB = someOtherConcreteImplementation;

var someModule = require('pathToSomeModule');

someModule(depA, depB);
import 'reflect-metadata';
import { ReflectiveInjector, Injectable, Injector } from 'injection-js';

class Http {}

@Injectable()
class Service {
  constructor(private http: Http) {}
}

@Injectable()
class Service2 {
  constructor(private injector: Injector) {}

  getService(): void {
    console.log(this.injector.get(Service) instanceof Service);
  }

  createChildInjector(): void {
    const childInjector = ReflectiveInjector.resolveAndCreate([
      Service
    ], this.injector);
  }
}

const injector = ReflectiveInjector.resolveAndCreate([
  Service,
  Http
]);

console.log(injector.get(Service) instanceof Service);