Angular 4依存注入チュートリアルの8 InjectTokenの使用


目次
  • Angular 4依存注入チュートリアルの1つ依存注入概要
  • Angular 4依存注入チュートリアルの2コンポーネントサービス注入
  • Angular 4依存注入チュートリアルの3 ClassProviderの使用
  • Angular 4依存注入チュートリアルの4 FactoryProviderの使用
  • Angular 4依存注入チュートリアルの5 FactoryProvider構成依存オブジェクト
  • Angular 4依存注入チュートリアルの6 Injectableアクセサリ
  • Angular 4依存注入チュートリアルの7 ValueProviderの使用
  • Angular 4依存注入チュートリアルの8 InjectTokenの使用
  • 読書の心得
    このチュートリアルの開発環境と開発言語:
  • Angular 4 +
  • Angular CLI
  • TypeScript

  • 基礎知識
    OpaqueTokenの概要OpaqueTokenは、Providerで使用可能なTokenを作成するために使用される.
    OpaqueTokenクラスの定義
    export class OpaqueToken {
      constructor(protected _desc: string) {}
    
      toString(): string { return `Token ${this._desc}`; }
    }

    OpaqueTokenクラスの使用
    import { ReflectiveInjector } from '@angular/core';
    
    var t = new OpaqueToken("value");
    var injector = ReflectiveInjector.resolveAndCreate([
      {provide: t, useValue: "bindingValue"}
    ]);
    injector.get(t); // "bindingValue"

    InjectionTokenの概要InjectionTokenは、Providerで使用可能なTokenを作成するために使用される.
    InjectionTokenクラスの定義
    export class InjectionToken extends OpaqueToken {
      private _differentiate_from_OpaqueToken_structurally: any;
      constructor(desc: string) { super(desc); }
    
      toString(): string { return `InjectionToken ${this._desc}`; }
    }

    InjectionTokenクラスの使用
    import { ReflectiveInjector } from '@angular/core';
    
    var t = new InjectionToken("value");
    var injector = ReflectiveInjector.resolveAndCreate([
      {provide: t, useValue: "bindingValue"}
    ]);
    injector.get(t); // "bindingValue"

    InjectionToken InjectionTokenについて説明する前に、「ValueProviderの使用」という記事で紹介した内容を振り返ってみましょう.
    ValueProviderの使用
    @NgModule({
       ...,
       providers: [
        {
          provide: 'apiUrl',
          useValue: 'http://localhost:4200/heros'
        }
       ],
      bootstrap: [AppComponent]
    })
    export class AppModule { }

    HeroServiceサービスの更新
    @Injectable()
    export class HeroService {
        constructor(private loggerService: LoggerService,
            private http: Http,
            @Inject('apiUrl') private apiUrl) { }
    
        getHeros(): Observable> {
            this.loggerService.log('Fetching heros...');
            return this.http.get(this.apiUrl)
                .map(res => res.json())
        }
    }
    apiUrlアドレスの管理とメンテナンスをより容易にするために、ValueProviderおよびInject装飾器を利用した.すべては順調に見えますが、ある日、サードパーティ製ライブラリthird-lib.tsを導入したと仮定します.このファイルの内容は次のようになります.
    export const THIRD_PARTY_PROVIDERS = [
        {
            provide: 'apiUrl',
            useValue: 'Other Url'
        }
    ];

    次に、AppModuleに対応するProvider情報を構成します.具体的には、以下のようにします.
    import { THIRD_PARTY_PROVIDERS } from './third-party';
    
    @NgModule({
       ...,
       providers: [
        {
          provide: 'apiUrl',
          useValue: 'http://localhost:4200/heros'
        },
        THIRD_PARTY_PROVIDERS
       ],
      bootstrap: [AppComponent]
    })
    export class AppModule { }

    上記のコードを更新し、保存に成功すると、http://localhost:4200/ページが空っぽになります.開発者ツールを開いてConsoleパネルに切り替えると、次のような異常情報が表示されます.
    GET http://localhost:4200/Other%20value 404 (Not Found)

    どのような状況で、私たちの英雄情報のインタフェースアドレスが置き換えられたのか、実は本当の原因は文字列をTokenとして使用して衝突したからです.では、どうやって解決しますか?最も簡単な方法は、ValueProviderTHIRD_PARTY_PROVIDERSの位置を調整することです.http://localhost:4200/ページには、ヒーローの情報も表示されます.もちろん、導入したサードパーティ製ライブラリが正常に動作しないため、本質的な問題を解決することはできません.
    多くの読者が私の「やり方」に慣れていると信じています.もちろん、私たちの主役であるInjectionTokenを出馬させて、この問題を解決します.アプリケーション内のToken情報を統一的に管理するために、アプリケーション内のapp.tokens.ts情報を保存するために、Tokenファイルを新規作成しました.この書類の具体的な内容は以下の通りです.
    import { InjectionToken } from '@angular/core';
    
    export const API_URL = new InjectionToken('apiUrl');

    次にAppModuleを更新します.
    import { API_URL } from './app.tokens';
    
    @NgModule({
       ...,
       providers: [
        {
          provide: API_URL,
          useValue: 'http://localhost:4200/heros'
        },
        THIRD_PARTY_PROVIDERS
       ],
      bootstrap: [AppComponent]
    })
    export class AppModule { }

    その後、HeroServiceサービスを更新し、具体的な更新内容は以下の通りである.
    import { API_URL } from './app.tokens';
    
    @Injectable()
    export class HeroService {
      constructor(private loggerService: LoggerService,
        private http: Http,
        @Inject(API_URL) private apiUrl) { }
    }

    上記のコードを更新し、保存に成功すると、http://localhost:4200/ページが表示され、ヒーロー情報が正常に表示されます.問題は解決しましたが、これは私たちが異なるTokenを使用しているからです.問題を検証します.
    import { InjectionToken } from '@angular/core';
    
    const API_URL = new InjectionToken('apiUrl');
    
    export const THIRD_PARTY_PROVIDERS = [
        {
            provide: API_URL,
            useValue: 'Other value'
        }
    ];
    third-lib.tsライブラリの更新が完了し、保存に成功した後、http://localhost:4200/ページに英雄情報が正常に表示されるかがわかります.この時点で、Angular 4依存注入チュートリアルは終了しましたが、このチュートリアルではAngular依存注入の一部の知識しか紹介していません.読者が興味を持っている場合は、以下の内容を引き続き理解することができます.
  • Angular 4.x Provider
  • は、useClass、useValue、useExisting、useFactory、およびProviderの使用方法に関する.

  • Angular 4.x Multi Providers
  • はmulti provider作用及びAngular 4に関する.x内部アプリケーション.

  • Angular 4.x Forward Reference
  • はforwardRefの役割と内部動作原理に関し、JavaScript解釈器がClassを自動的に昇格させることができないことを説明する.

  • Angular 4.x OpaqueToken & InjectionToken
  • は、Tokenとして文字列を使用することに関する問題があり、OpaqueToken、InjectionTokenを使用して問題を解決する方法について詳しく説明します.

  • Angular 4.x IoC & DI
  • は、IoCおよびDIに関するAngularJS 1.xにおける応用、内部動作原理及び存在する問題等.

  • Angular 4.x Injector
  • は依存注入の概念及びAngular 4に関する.x注入器の内部実装(慎重).

  • Angular Element Injector
  • はまだ完成していません.
  • をお楽しみください.

    話があるんだ
    OpaqueTokenとInjectionTokenの違いは何ですか?
    同じ点
  • は、Providerで使用可能なTokenを作成するために使用される.

  • 異なる点
  • OpaqueTokenAngularである.xバージョンに導入されたクラス.
  • InjectionTokenAngularである.xバージョンで導入されたクラス.このクラスはOpaqueTokenに継承され、関連する依存オブジェクトを定義するために汎用的なタイプが導入されています.

  • AngularJS 1.xDIシステムの問題点
  • 内部キャッシュ:AngularJS 1.xアプリケーションのすべての依存項目は単一の例であり、新しいインスタンスを使用するかどうかを柔軟に制御することはできません.
  • ネーミングスペース競合:システムでは文字列を使用してサービス(Service)の名前を識別します.プロジェクトにCarServiceがあると仮定しますが、サードパーティのライブラリにも同様のサービスが導入されているため、競合が発生しやすくなります.
  • DI結合度が高すぎる:AngularJS 1.x中のDI機能はすでにフレームワークに統合されており,その依存注入機能を単独で使用することはできない.
  • モジュールローダと結合できませんでした:ブラウザ環境では、多くのシーンが非同期のプロセスであり、私たちが必要とする依存モジュールは最初からロードされているわけではありません.私たちは作成時に依存モジュールをロードし、依存作成を行うかもしれません.AngularJS 1.xのDIシステムではそれができません.