AngularJSからAngularへの移行:AngularJS後の生活(3/3)







Angularへの移行に関するストーリーの最後の部分では、開発者が新しいフレームワークに慣れるのに役立つ内部ドキュメントの選択された場所を共有します。 新しいコンポーネントコンパイルロジックの機能、変更検出、およびトランスクルージョンの概念について説明します。 これらは、Angularで作業するときに現在使用されている現在の規則です。 さて、最後に-同僚におすすめする英語の記事やビデオへのリンク。







前のシリーズ: 最初は移行の準備について2番目はハイブリッドモードで作業する機能についてです







アプリケーションとAoTのコンパイル



Angularの主な変更点の1つは、コンポーネントのコンパイルロジックです。







AngularJSでは、最初のコンポーネント(一番上のコンポーネント)のHTMLを取得し、DOMに詰め、ブラウザーがそれを解析するか、DOMフラグメントを構築するか、DOMに挿入するか、受信したDOMフラグメントへのリンクを取得し、その中の角形部分を解析します(ディレクティブ) 、コンポーネント)、見つかった各コンポーネントに対して繰り返されました。







Angularは、js / tsのテンプレートのコンパイルを2つのバリアント(JiTおよびAoT)で使用します。 アプリケーションの開始時に(JiTモードで)、フレームはHTMLを含む文字列からすべてのコンポーネントのすべての(一般的にすべての)テンプレートを取得してコンパイルし、目的のDOMピースを作成します。 つまり DOMフラグメントの解析と構築はブラウザにまったく依存せず、Angularは自分で行います。 その後、最上位のコンポーネントから開始して、対応する既製のJSコードの実行を開始します。これにより、DOMの断片が作成され、ツリー内の目的の場所にすぐに挿入されます。 挿入後、追加の解析は必要ありません。 コンパイラはすでにすべてを解析しています。







AoTコンパイルは、アセンブリ中にサーバー上でローカルに実行されます。少し時間がかかりますが、出力はTSファイルの形式で別のディレクトリにあるすべてのコンポーネントのデータを提供します。 それらはメインアプリケーションにしがみつき、TypeScriptのコンパイルはすでにコピーされたテンプレートを考慮しています。







AoTモードでは、テンプレートはJSではなくTypeScriptでコンパイルされます。 これにより、すべてのパターンの静的な型指定が可能になります。 変数をスキップし、プライベートとして指定したか、不適切に処理しました(文字列を待機しているコンポーネントの入力にオブジェクトを押し込もうとした)-アセンブリ中にエラーが発生しました。 ただし、これは実稼働用のビルドモードのみです。 大量の型付きコードが追加されたため、アセンブリ(コンパイルts-> js)が少し遅くなり、開発中にAoTモードがオフになります(マルチスレッドコンパイルの楽しい時や、AoTを開発モードで使用するための苦労を待っています)。







トピックに関するリンク: firstsecondおよびthird







変更検出(CD)



Angularにはグローバルダイジェストサイクル(および変更可能なパラメータのリストがあり、チェックする必要があります)がなくなり、ネイティブイベントバインディング( addEventListener



など)が最大限に使用されますが、検出エンジン自体は消えていません。







個別のイベントディレクティブとタイムアウト/間隔の特別なサービスなしで何かが起こったことをAngularはどのように知っていますか?







Angularの別個のバージョンがあるDart言語から、ゾーンの有用な概念を借用しました。これにより、特定のゾーンでコードの実行が開始されたタイミングと、非同期呼び出しを考慮して終了したタイミングを知ることができます。 これはすべてzone.js libで形になりました 。これにより、このようなゾーンを作成/操作でき、Angularエンジン内で積極的に使用されます。 非同期イベントに遅れないようにするために、zone.jsは対応するメソッド-addEventListener、 setTimeout



setInterval



Promise



メソッドなどをデコイ(そのバージョンに置き換え)しsetInterval



。 これにより、イベント/追加サービスにバインドするための個別のディレクティブが不要になりました。 したがって、zone.jsでキャッチされたイベントの最後に、Angularは変更検出をプルして、モデルをDOMと同期します。 開発モードでは、検出は2回作動します。2回目は、1回目以降は何も変更されていないことを確認するか、変更された場合は(コンソールのエラー)を与えます。 本番環境では、常に1回だけです(ダイジェストサイクルと対応するエラーの呼び出しが10倍になりません)。







チェックされたパラメータのグローバルプールがない場合、変更検出はどのように行われますか







これは、コンポーネントの作業です。 それぞれに、DOMまたは特別なバインディング( HostBinding



など)で何らかの形で使用されるパラメーターのセットをHostBinding



ことができます。 そのようなパラメータは、コンポーネント内の個別のリストに格納されます(他のどこにも知られていない)。







Angularがグローバル検出変更ログを取得すると、各コンポーネント(ツリーの上部から下部)自体がパラメーターのチェックに関与します。 同時に、変更検出メカニズムをコンポーネントから切り離すことができ、そのパラメーターは原則としてチェックされません。 または、入力の変更のみをチェックするように構成することができ( ChangeDetectionStrategy.OnPush



)、何もチェックしないだけでなく、それに含まれるコンポーネント/ディレクティブのチェックの開始を完全に遮断します。 したがって、 OnPush



が正しく分散されているため、各ティックのスキャンからコンポーネントのブランチ全体を除外できます。







また、Angularゾーンの外部または(明示的に)コードの一部を実行することもできます(Angularゾーンでは、イベントなどをキャッチします)。 これは、これらすべてのトラブルをごまかすためにサードパーティ製のライブラリに固執する場合に役立ちます。 また、ライブラリ内のすべてのイベントやタイムアウトに対して、コンポーネントツリー全体でけいれんが発生することはありません。 後でデータを更新したことを角度に伝えるために(彼が聞いていたゾーンの外部で起動されたこのlibから取得)、角度ゾーンで何らかのアクション(たとえば、コンポーネントのローカルプロパティの変更)の実行を明示的に規定します。







detectChangesおよびmarkForCheck







分離されたCDまたはコンポーネント(ツリーの現在のコンポーネント以上)にChangeDetectionStrategy.OnPush



ChangeDetectionStrategy.OnPush



書き込まれ、自動的に取得されない変更がある場合、ローカルのChangeDetectorRef



サービスには2つのメソッドがありますdetectChanges



およびmarkForCheck











 if (!this.changeDetectorRef["destroyed"]) { this.changeDetectorRef.detectChanges(); }
      
      





使用する場合:









ng-content



- ng-transclude



と同じではありません



Angularのトランスクラッジの概念は少し変更されました(これがWebコンポーネントでどのように行われるか、およびエンジン/コンパイラの機能の影響を受けて)。 外部では、 ng-content



ng-transclude



と同じ機能を持ち、コンポーネントに何かを投げて、特定の場所に投げselect



(属性をselect



ます)。







ただし、1つの小さな違いがありますng-content



content内にデフォルトのコンテンツを指定する方法はありません-非常に重要なものです:このコンテンツをスローする人は、 ng-content



タグを含むコンポーネントではなく、 ng-content



ロールされるコンテンツの初期化を担当します。







例の説明:







 @Component({ ... template: ` Visible: {{ visible }} <ng-content *ngIf="visible"></ng-content> `, }) class ProjectionComponent implements OnInit { public visible = false; public ngOnInit() { window.setTimeout(() => this.visible = true, 1000); window.setTimeout(() => this.visible = false, 2000); } } @Component({...}) class ChildComponent implements OnInit, AfterViewInit, OnDestroy { public ngOnInit() { console.log("Child component ngOnInit"); } public ngAfterViewInit() { console.log("Child component ngAfterViewInit"); } public ngOnDestroy() { console.log("Child component ngOnDestroy"); } } @Component({ ... template: ` <vim-projection> <vim-child-component></vim-child-component> </vim-projection> `, }) class ParentComponent {}
      
      





ProjectionComponent



とコンソールログでngIf









 //    `Visible`   `ProjectionComponent` Child component ngOnInit //   Child component ngAfterViewInit //  2  // …
      
      





最初の1秒では、 *ngIf="false"



にもかかわらず、 ChildComponent



が初期化され( OnInit



フックが機能)、 OnDestroy



は2秒後にOnDestroy



しませんでしたが、コンポーネントは非表示になったようです。







つまり ng-content



を含むコンポーネントで何が起こっても、そこにスローされるものはすべて初期化されます( OnInit



フックが呼び出されます)。 これは、コンポーネントの初期化で要求、重い処理などがある場合に重要です。







そのようなコンテンツを非表示にする必要がある場合は、それをスローする人がこれを行う必要があります。







 <vim-projection> <vim-child-component *ngIf="visibleInParent"></vim-child-component> </vim-projection>
      
      





または、TemplateRefを使用してこの制限を回避する興味深い方法を使用します。







 <div *ngIf="condition" class="smth1"> <ng-container *ngTemplateOutlet="contentTpl"></ng-container> </div> <div *ngIf="!condition" class="smth2"> <ng-container *ngTemplateOutlet="contentTpl"></ng-container> </div> <div *ngIf="condition2" class="smth1"> <ng-container *ngTemplateOutlet="contentWithSelectorTpl"></ng-container> </div> <div *ngIf="!condition2" class="smth2"> <ng-container *ngTemplateOutlet="contentWithSelectorTpl"></ng-container> </div> <ng-template #contentTpl><ng-content></ng-content></ng-template> <ng-template #contentWithSelectorTpl><ng-content select="[some-attribute]"></ng-content></ng-template>
      
      





制限事項-このようなng-content



を一度に挿入できるのは1箇所のみです。







また、 ng-content



では、テンプレートに複数の同一のスロットを指定することはできません。同じスロットを表示すると、条件がハングします。







 <!--   --> <div *ngIf="smth" class="smth1"> <ng-content></ng-content> </div> <div *ngIf="!smth" class="smth2"> <ng-content></ng-content> </div> <!--    --> <div *ngIf="smth" class="smth1"> <ng-content select="[some-selector]"></ng-content> </div> <div *ngIf="!smth" class="smth2"> <ng-content select="[some-selector]"></ng-content> </div>
      
      





有用な資料へのリンク



Googleでは、角度2+に多くのことがあります。すぐに/ドックで不明なトピックを安全に検索できます。 リリースから(そしてそれ以前)人々はフレームをパーツに分解し、それがどのように機能するかを理解していました。







便利なリンクを次に示します。







ElementRef、TemplateRef、ViewContainerRef







構造ディレクティブ1







構造ディレクティブ2







ViewChildren、ContentChildren、QueryList







動的コンポーネント1







動的コンポーネント2







変更検出







ng-templateと構造ディレクティブのマイクロ構文







そして最後に、いつものように、 Angularだけでなくクールな開発者を常に探していることを思い出させてください。








All Articles