Transclusion, Injection and Procrastination

Exploring The Hidden Corners of Angular Dependency Injection

A few months ago, Kapunahele Wong and I were brainstorming ideas for talk proposals we could do together. ちょうど私が Ivy を探求することを決めた頃だったので、これは講演に適していると思いました。

Twitter, where the fun stuff is happening!

Injector Trees について初めて聞いたので、興味をそそられました。 Kapunahele が事前調査の一部を共有してくれたので、Angular Injector の依存関係解決アルゴリズムが以前考えていたほど単純ではないことを知りました。

実際、NgModules は Angular 2.0 の第 5 リリース候補で導入されたので、そのときから、NgModules を使用するようになりました。

または Angular 6 からは、Injectable デコレーターの providedIn プロパティを使用します。

どちらにしても、常にモジュール レベルでサービスを宣言し、他の可能性にはあまり注意を払わなかったのです。

Enter Injector Trees 🌴

Kapunahele と私は、Injector Trees の話を Angular Connect に提出することにしました。 数か月後、次のメッセージが私の受信トレイに届きました:

We were pumped, our talk was accepted for the conference! 😊

私たちはその後の数週間、依存性注入が Angular でどのように機能するかのすべての隠れたコーナーを探検しました。 このブログ記事では、そのうちのいくつかを紹介します。

Starting Simple

まずは、シンプルな Angular アプリから始めましょう。 このアプリには「Kingdom」サービスと、Kingdom を注入してその名前を表示する単一のコンポーネントがあります。

私はコードでセミコロンの代わりにドラゴンを使うのが好きなので、この例ではドラゴンを使うことにしました。

もう少し面白くするために、このアプリに Unicorn コンポーネントを追加しましょう。 このコンポーネントは、自分が住んでいる王国の名前を表示します。

つまり、アプリ コンポーネントと、その中のユニコーンがあるわけです。 素晴らしい!

さて、 に異なる値を提供するために AppComponent の定義を変更するとどうなるでしょうか。

これを行うには、次の行をコンポーネント宣言に追加します。

見てのとおり、AppComponentKingdomService に定義した値は、AppModule で定義したサービスよりも優先されました (直接定義したのではなく、providedIn を使用しましたが、結果は同じです)。

要素ツリー、モジュール ツリー

ゾンビが見られる理由は、依存性解決が Angular で働く方法だからです。 最初にコンポーネントのツリーを検索し、その後でモジュールのツリーを検索します。 UnicornComponent を考えてみましょう。

constructor(public kingdom: KingdomService) {}

このコンポーネントを作成するとき、Angular はまずコンポーネントと同じ要素に定義されているプロバイダーがあるかどうかを調べます。 これらのプロバイダーは、コンポーネント自体に登録されているか、ディレクティブを使用して登録されている可能性があります。 この場合、UnicornComponent 内で KingdomService の値を指定していませんし、<app-unicorn> 要素にディレクティブもありません。

次に、検索は要素ツリーを上がっていき、AppComponent まで行きます。 ここでAngularはKingdomServiceに値があることを発見し、この値を注入してそこで検索を停止します。

Angular is Lazy!

私たちプログラマーと同じように、Angular もまた、先延ばし主義者なのです。 本当に必要でない限り、サービスのインスタンスを作成しません。 KingdomService のコンストラクタに console.log ステートメントを追加することでこれを確認できます(今日懐かしさを感じるなら alert('I love marquees') を追加することもできます)

この console.log ステートメントは実行されないことがわかります – Angular はサービスを作成しないので。 AppComponent から providers: の宣言を削除すると(または UnicornComponent に移動して、unicorn とその子要素にのみ適用します)、コンソールにログメッセージが表示されるようになるはずです。 そこで、まずモジュールインジェクターツリーに移動し、そこでサービスを提供することを確認し、最後にそのインスタンスを作成します。 したがって、コンストラクター内のコードが実行され、そこに入れたデバッグ出力を見ることができます。

Directive Invasion!

ディレクティブも依存性注入の値を提供できることを述べました。 それを実験してみましょう。 これから新しい appInvader ディレクティブを定義し、王国の値を 👾 に変更します。
なぜですか? ng-conf で Alex Castillo と私が行った VR + Angular トークで、ユニコーンがとてもかわいかったからです。

次に、別の <app-unicorn> 要素を追加し、新しい appInvader ディレクティブをそれに適用します:

予想どおり、新しいユニコーンは👾の王国に住んでいます。 これは、ディレクティブがKingdomServiceの値を提供したためです。 そして、上で説明したように、Angular は現在の要素から検索を開始し、コンポーネントとすべてのディレクティブを見て、そこで要求された値を見つけることができない場合のみ、要素ツリー (そしてモジュール) を上昇し続けます。

私たちのアプリに新しいフォレスト コンポーネントを追加し、ユニコーンの一部をこのフォレスト内に配置します。

フォレスト コンポーネントは単なるコンテナーで、コンテンツ プロジェクションを使用して、緑の「フォレスト」背景の上に子コンポーネントを表示します。 そして、アプリ コンポーネント内で KingdomService の値を提供したので、内部のすべてはそれを継承します (appInvader ディレクティブを持つ 1 つのユニコーンを除く)。

しかし、ForestComponent 内で KingdomService に新しい値を提供するとどうなるでしょうか。 投影されたコンテンツ(AppComponentのテンプレートで定義されたもの)も、この王国の新しい値を取得するのでしょうか? それとも、まだ🧟王国になるのでしょうか? 9009>

以前は Transclusion と呼ばれていました。 今は「Content Projection」と呼ばれています。 Photo by ng-conf

The Wizard of The Forest

前の例に 1 行追加して、ForestComponent:

providers: 

そしてこれが結果です:

さてこれは興味深いです – 私たちは森の中の王国の混合を見ます!

AppComponentインスタンスのkingdomプロパティを読み込んでいます。 このコンポーネントの DOM 要素は、実際には <app-forest> DOM 要素の先祖にあたります。 したがって、この AppComponent インスタンスが作成されたときに、🧟王国が注入されました。

ただし、2 つの <app-unicorn> 要素は <app-forest> DOM 要素内にあり、それらの UnicornComponents インスタンスが作成されると、angular は実際に DOM 上に移動して ForestComponent 内の KingdomService に指定した値を見て、これらのユニコーンは🧙国が注入されました。

ForestComponentを定義する際にprovidersviewProvidersに変更すれば、別の動作を実現することができます。 また、このコード例では、ForestComponent を変更してビュープロバイダを使用し、森の中のユニコーンにも 🧟王国を注入しています。 これを指摘してくれた Lars Gyrup Brink Nielsen に感謝します!

Chrome T-Rex はこのブログ記事

Keep Exploring でトランスコードしておきました!

Angular の依存性注入システムに関して、何か新しいことを学んでいただけたでしょうか。 これは、Kapunahele と私が AngularConnect での講演を準備する際に調べたことのほんの 1 つです。 また、講演後にスライドとビデオへのリンクも共有します。 さらに、ライブコーディングも予定しています。 とても楽しいイベントになりそうです。

Angular Injector の内部と外部についてもっと学びたい場合は、私が非常に役に立ったと思う記事をいくつか紹介します。

  • What you always wanted to know about Angular Dependency Injection
  • A curious case of the @Host decorator and Element Injectors in Angular
  • Hierarchical Dependency Injectors (Angular Docs)

そして AngularConnect に参加していたら、ぜひ会いに来てくださいね!

!

コメントを残す

メールアドレスが公開されることはありません。