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