angular-master\packages\core\src\di\interface\provider.ts数组
export interface ClassSansProvider { useClass: Type<any>; } export interface ClassProvider extends ClassSansProvider { /** *一个注入令牌。(一般是' Type '或' InjectionToken '的实例,但也能够是' any */ provide: any; /** 当为true时,注入器返回一个实例数组。这对于容许多重是颇有用的 提供商跨越多个文件,为一个公共令牌提供配置信息。 */ multi?: boolean; }
export interface ValueSansProvider { /** * 要注入的值 */ useValue: any; } export interface ValueProvider extends ValueSansProvider { provide: any; multi?: boolean; }
useExisting
的意思是使用已经注册的类型注入到这里(别名)ide
export interface ExistingSansProvider { /** *现有的“令牌”要返回。(至关于“injector.get (useExisting)”) */ useExisting: any; } export interface ExistingProvider extends ExistingSansProvider { provide: any; multi?: boolean; }
export interface FactorySansProvider { /** 调用一个函数来为这个“令牌”建立一个值。函数被调用 *解决了' token '的值在' deps '字段 */ useFactory: Function; /* *用做' useFactory '函数的参数。 */ deps?: any[]; } export interface FactoryProvider extends FactorySansProvider { provide: any; multi?: boolean; }
Injector
是new
操做符的替代品,它能够自动解析函数
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