iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 5
1
Modern Web

從巨人的 Tip 看 Angular系列 第 5

[Day 5] 在建立 InjectionToken 的時候加入 Dependency

  • 分享至 

  • xImage
  •  

昨天提到可以 InjectionToken 這個類別來建立一個 DI Token,而且也可以在建立 DI Token 的時候提供建立實體用的工廠方法,那如果要提供的實體有其他的相依關係時,該怎麼辦?

這就是今天要介紹的 Tip:在建立 Token 時的工廠方法提供相依物件!

延續昨天的架構,在實作 IMyService 介面的 MyService 類別上加入 MyDepService 類別,建立 MyService 與 MyDepService 的相依關係:

export interface IMyService {
  print(): string;
}

export class MyService implements IMyService {

  constructor(private readonly myDep: MyDepService) {}

  print(): string {
    return this.myDep.hello();
  }
}

↑ Block 1

接著就可以建立一個帶有工廠方法的 InjectionToken 物件。建立工廠方法時,若要建立的物件需要其他相依性,就可以透過 inject 這個函式,請 Angular 從 injector 中取出相依物件的實體:

export const MY_SERVICE_TOKEN = new InjectionToken<IMyService>('My Service', {
  providedIn: 'root',
  factory: () => new MyService(inject(MyDepService))    
});

↑ Block 2

透過 Block 2 的方式建立 InjectionToken 後,只要是使用 MY_SERVICE_TOKEN 注入,Angular 就會自動幫你處理 MyService 類別的相依性問題了。

好奇就爬 code 啦,哪次不爬的

這次因為好奇 inject 函式到底做了什麼,所以就來爬 code 了,首先它的實作如下:

export const inject = ɵɵinject;

export function ɵɵinject<T>(token: Type<T>|InjectionToken<T>): T;
export function ɵɵinject<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags): T|null;
export function ɵɵinject<T>(token: Type<T>|InjectionToken<T>, flags = InjectFlags.Default): T|null {
  return (_injectImplementation || injectInjectorOnly)(resolveForwardRef(token), flags);
} 

想要知道 ɵɵinject 函式最後是使用 _injectImplementation 還是 injectInjectorOnly 來處理 MyDepService 可以按以下的順序來爬:

  1. 找 Angular 在編譯後協助解析 MY_SERVICE_TOKEN 的函式(本例是 ɵɵdirectiveInject
  2. 呼叫 getOrCreateInjectable 函式
    1. tNode 是否為 null(本例為否)
    2. bloomHash 的型別是否為 function 或 number(本例為否)
    3. (flags & (InjectFlags.Self | InjectFlags.Host)) 是否等於 0(本例為是)
    4. 呼叫 setInjectImplementation 函式,將 _injectImplementation 設為 undefine
    5. 使用 moduleInjector(本例為 R3Injector) 取得物件實體
      1. 呼叫 setCurrentInjector 函式,將 _currentInjector 設為 R3Injector 的實體
      2. 呼叫 hydrate 方法
        1. 發現這個 token 的物件實體沒有被建立過
        2. 呼叫 provider 的工廠方法,建立 MyService
          1. 呼叫 ɵɵinject 函式取得 MyDepService

到最後實際呼叫 ɵɵinject 函式時,_injectImplementation 就會是 undefine 的狀態,所以自然而然就會使用 injectInjectorOnly 這個函式來取得 MyDepService 的實體,並注入到 MyService 的 constructor 囉!


繼續加油!

以下按照入團順序列出我們團隊夥伴的系列文章!


上一篇
[Day 4] @Inject(token: InjectionToken<T>)!
下一篇
[Day 6] NG_VALIDATOR,自訂表單驗證器的二三事
系列文
從巨人的 Tip 看 Angular30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言