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

相關文章
相關標籤/搜索