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);