角度反射注射器与注射器的区别

Cod*_*-EZ 2 dependency-injection angular

我试图用两种方式明确地创建依赖.两者几乎相同,但我有点混淆使用反射注射器优于普通注射器的优势以及推荐使用哪一种?

使用注射器

import { Injector } from '@angular/core';
constructor( private injector: Injector) {
    this.myService = this.injector.get(MyService);
  }
Run Code Online (Sandbox Code Playgroud)

使用反射注射器

import { ReflectiveInjector } from '@angular/core';
 constructor() {

       var injector= ReflectiveInjector.resolveAndCreate([MyService]);
       let myservice=injector.get(MyService);
     }
Run Code Online (Sandbox Code Playgroud)

Max*_*kyi 5

注入器是具有提供者/服务的容器.它实现一个方法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 });
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,我们需要在使用它之前创建注入器的实例.当我们创建它时,我们定义提供者:

const existingInjector = ReflectiveInjector.resolveAndCreate([{provide: A, useClass: A }]);
const AInstance = existingInjector.get(A);
Run Code Online (Sandbox Code Playgroud)

所以你看,为了使用注射器,必须首先创建它.它没有任何允许添加提供程序的特定方法,因此在创建之后我们无法向其添加任何新提供程序.

注入组件构造函数的注入器已由Angular 创建.您无法向其添加任何内容,只能查询已在其上定义的提供程序.如果您需要提供B课程,则不能使用现有的注射器.你需要一个新的.这就是ReflectiveInjector类的用武之地.它允许您通过创建注入器的新实例并注册新的提供程序来添加新的提供程序.好的部分是它还可以设置喷射器链.

让我们稍微修改resolveAndCreateget允许链接注入器的方法:

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;
   }
Run Code Online (Sandbox Code Playgroud)

所以现在唯一剩下的就是使用它:

// passing existingInjector as a parent
const childInjector = ReflectiveInjector.resolveAndCreate([{provide: B, useClass: B }], i);
const AInstance = childInjector.get(A);
const BInstance = childInjector.get(B);
Run Code Online (Sandbox Code Playgroud)

现在,假设某人可能想要访问我们的existingInjector.我们需要一个令牌来获取这个现有的注入器.让我们像这样定义这个标记:

abstract class Injector {}
Run Code Online (Sandbox Code Playgroud)

让我们编写一个能够获得现有注入器的函数:

function resolveDependency(token) {
   if (token === Injector) {
       return existingInjector;
   }
}
Run Code Online (Sandbox Code Playgroud)

现在假设Angular在执行组件的构造函数时,使用您指定的标记来获取依赖项并将它们传递给resolveDependency函数.所以你这样写:

// the Injector here is a reference to our abstract Injector class and simply used as a token
MyComp {
   constructor(private injector: Injector) { ...  }
}
Run Code Online (Sandbox Code Playgroud)

这里的令牌Injector就像我说的那样传递给resolveDependency函数并返回现有的注入器.

  • @JEMI如果您能够在模块中注册它们,则根本不应使用ReflectiveInjector.在极少数情况下应该动态完成.它是AngularJS中`angular.inject`的直接对应物,并且`angular.inject`在99%的时间内被误用. (2认同)