angular11源码探索九[服务源码实践理解]

angular-master\packages\core\src\di\interface\provider.ts数组

useClass

export interface ClassSansProvider {
  useClass: Type<any>;
}
export interface ClassProvider extends ClassSansProvider {
  /**
   *一个注入令牌。(一般是' Type '或' InjectionToken '的实例,但也能够是' any 
   */
  provide: any;

  /**
  当为true时,注入器返回一个实例数组。这对于容许多重是颇有用的
   提供商跨越多个文件,为一个公共令牌提供配置信息。
   */
  multi?: boolean;
}

useValue

export interface ValueSansProvider {
  /**
   * 要注入的值
   */
  useValue: any;
}
export interface ValueProvider extends ValueSansProvider {
  provide: any;
  multi?: boolean;
}

useExisting

useExisting 的意思是使用已经注册的类型注入到这里(别名)ide

export interface ExistingSansProvider {
  /**
   *现有的“令牌”要返回。(至关于“injector.get (useExisting)”)
   */
  useExisting: any;
}
export interface ExistingProvider extends ExistingSansProvider {
  provide: any;
  multi?: boolean;
}

useFactory

export interface FactorySansProvider {
  /**
  调用一个函数来为这个“令牌”建立一个值。函数被调用
*解决了' token '的值在' deps '字段
   */
  useFactory: Function;
    /*
    *用做' useFactory '函数的参数。
    */
  deps?: any[];
}
export interface FactoryProvider extends FactorySansProvider {
  provide: any;
  multi?: boolean;
}

Injectornew操做符的替代品,它能够自动解析函数

  • 构造函数依赖关系。
  • 在典型的使用中,应用程序代码请求构造函数中的依赖项,它们确实是由Injector解析。
解析一个提供商数组,并从这些提供商建立一个注入器。

*传入的提供商能够是一个数组
*或更多提供程序的递归数组。
let injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
// 拿到第一个
let car = injector.get(Car);
一个扁平化多个嵌套数组和转换个别的过程
将providers转换为数组
    @Injectable()
     class Engine {
    }
    @Injectable()
    class Car {
      constructor(public engine:Engine) {}
    }
let providers = ReflectiveInjector.resolve([Car, [[Engine]]]);
providers.length  //2
providers[0].key.displayName    // "Car"
providers[1].key.displayName   // "Engine"
*从以前解析的提供商建立注入器。
*
*本API是在性能敏感部件中构造喷油器的推荐方法。
var providers = ReflectiveInjector.resolve([Car, Engine]);
var injector = ReflectiveInjector.fromResolvedProviders(providers);
injector.get(Car)  // Car
解析一个提供商数组,并从这些提供商建立一个子注入器。
var parent = ReflectiveInjector.resolveAndCreate([ParentProvider]);
var child = parent.resolveAndCreateChild([ChildProvider]);
child.get(ParentProvider) instanceof ParentProvider  //true
child.get(ChildProvider) instanceof ChildProvider // true
// 牛逼啦  子找父  === 总找父
child.get(ParentProvider)  //  parent.get(ParentProvider)
  • DI 解析 Providers 时,都会对提供的每一个 provider 进行规范化处理,即转换成标准的形式
function _normalizeProviders(
    providers: Provider[], res: NormalizedProvider[]): NormalizedProvider[] {
  providers.forEach(b => {
    if (b instanceof Type) {
      res.push({provide: b, useClass: b} as NormalizedProvider);

    } else if (b && typeof b == 'object' && (b as any).provide !== undefined) {
      res.push(b as NormalizedProvider);

    } else if (Array.isArray(b)) {
          // 若是是数组,进行递归处理
      _normalizeProviders(b, res);

    } else {
      throw invalidProviderError(b);
    }
  });

  return res;
}

在开发过程当中咱们可能会遇到相似下面这样的问题性能

@Injectable()
class Socket {
  constructor(private buffer: Buffer) { }
}

console.log(Buffer)  // undefined

@Injectable()
class Buffer {
  constructor(@Inject(BUFFER_SIZE) private size: Number) { }
}

console.log(Buffer)  // [Function: Buffer]

// 运行后报错

因此在编译阶段「变量声明和函数声明会自动提高,而函数表达式不会自动提高」this

若是要解决上面的问题,最简单的处理方式是交换类定义的顺序,或者还可使用 Angular 提供的 forward reference 特性,Angular 经过引入 forwardRef 让咱们能够在使用构造注入的时候,使用还没有定义的依赖对象类型,code

咱们看看forwardRef原理orm

容许引用还没有定义的引用。
*
*例如,' forwardRef '用于咱们须要引用的' token '的目的
DI已声明,但还没有定义。它也用于咱们建立时使用的token
*查询还没有定义。

export function forwardRef(forwardRefFn: ForwardRefFn): Type<any> {
// 当调用 forwardRef 方法时,咱们只是在 forwardRefFn 函数对象上,增长了一个私有属性__forward_ref__
  (<any>forwardRefFn).__forward_ref__ = forwardRef;
     // 而后覆写了函数的 toString 方法
  (<any>forwardRefFn).toString = function() {
    return stringify(this());
  };
  return (<Type<any>><any>forwardRefFn);
}

若是所建立的服务不依赖于其余对象,是能够不用使用 @Injectable() 类装饰器,但当该服务须要在构造函数中注入依赖对象,就须要使用 @Injectable() 装饰器,由于只有声明了 @Injectable() 这个装饰器的服务才能够注入其余服务对象

推荐的作法无论是否有依赖对象,在建立服务时都使用 @Injectable() 类装饰器,这样全部服务都遵循一样的规则,一致性blog

相关文章
相关标签/搜索