注入器是带有提供者/服务的容器。它实现了一个方法get 并返回服务的一个实例。让我们用 JS 伪代码实现最基础的注入器版本:
class ReflectiveInjector {
providers = [];
static resolveAndCreate(providers) {
providers.forEach((provider)=>{
providers.push({token: provider.provide, instance: new provider.useClass})
});
)}
get(dep) {
return providers.find((provider)=>{ return provider.token === token });
}
}
现在,我们需要先创建注入器的实例,然后才能使用它。当我们创建它时,我们定义了提供者:
const existingInjector = ReflectiveInjector.resolveAndCreate([{provide: A, useClass: A }]);
const AInstance = existingInjector.get(A);
所以你看,为了使用一个注入器,它必须首先被创建。它没有任何允许添加提供程序的特定方法,因此在创建它之后我们不能向它添加任何新的提供程序。
您注入到组件构造函数中的注入器已经由 Angular 创建。您不能向其中添加任何内容,只能查询已在其上定义的提供程序。如果你需要提供B 类,你不能用现有的注入器来做到这一点。你需要一个新的。这就是ReflectiveInjector 类的用武之地。它允许您通过创建注入器的新实例并注册新提供者来添加新提供者。好在它还可以设置一个注入器链。
让我们稍微修改一下resolveAndCreate 和get 方法以允许链接注入器:
class ReflectiveInjector {
providers = [];
parent;
static resolveAndCreate(providers, parent) {
this.parent = parent;
...
}
get(dep) {
let found = providers.find((provider)=>{ return provider.token === token });
if (!found && parent) {
found = parent.get(dep);
}
return found;
}
所以现在唯一剩下的就是使用它了:
// passing existingInjector as a parent
const childInjector = ReflectiveInjector.resolveAndCreate([{provide: B, useClass: B }], i);
const AInstance = childInjector.get(A);
const BInstance = childInjector.get(B);
现在,假设有人可能想要访问我们的existingInjector。我们需要一个令牌来获取这个现有的注入器。让我们像这样定义这个令牌:
abstract class Injector {}
让我们编写一个函数来获取现有的注入器:
function resolveDependency(token) {
if (token === Injector) {
return existingInjector;
}
}
现在假设 Angular 在执行组件的构造函数时,使用您指定的令牌来获取依赖项并将它们传递给 resolveDependency 函数。所以你这样写:
// the Injector here is a reference to our abstract Injector class and simply used as a token
MyComp {
constructor(private injector: Injector) { ... }
}
这里的令牌是Injector,正如我所说,它被传递到resolveDependency函数并返回现有的注入器。