クリーンで高速なAngularアプリケーションを作成する経験豊富

この記事の執筆は、Stavropolにある自社のJavaScriptフロントエンド開発者の検索によって促されました。 なぜなら 長い間、インテリジェントなプログラマーを見つけることができなかったため、Angular&JSに関する多くのトレーニング資料を含むインターンシッププログラムを開始することにしました。

これは、Angularで書かれたTrade Meの大規模アプリケーションに関する彼の経験に関するVamsi Vempatiの記事の翻訳です。



現在まで、私はTrade Meで大規模なAngularアプリケーションに数年取り組んできました。 過去数年にわたって、私たちのチームは、コード作成の標準とパフォーマンスの観点からアプリケーションを改良し、可能な限り最高の状態にしました。

この記事では、プロジェクトで使用する方法の概要を説明します。 テキストは主に、Angular、TypeScript、RxJ、および@ ngrx / storeに関連付けられています。

さらに、アプリケーションをより「クリーン」かつ読みやすくするのに役立つコードを記述するためのいくつかの一般的なガイドラインが考慮されます。

1)trackBy


ngForを使用してテンプレート内の配列をループする場合、 trackBy関数を参照します。この関数は、各要素の一意の識別子を返します。

なんで?


配列が変更されると、AngularはDOMツリーを完全に再描画します。 ただし、 trackBy関数を使用すると、Angularはどの要素が変更されたかを理解し、その特定の要素についてのみDOMを変更します。

注:より詳細な説明は Nathanel Bazalの記事にあります。 [eng]


 <li *ngFor="let item of items;">{{ item }}</li> 



 //   <li *ngFor="let item of items; trackBy: trackByFn">{{ item }}</li> //   trackByFn(index, item) { return item.id; // unique id corresponding to the item } 

2)constまたはlet?


変数を宣言するときに、再割り当てされない場合はconst使用します。

なんで?


必要に応じてletとconstを使用すると、変数を宣言する理由がわかりやすくなります。 また、コンパイル時エラーが原因で値が定数にランダムに再割り当てされる問題の特定にも役立ちます。 また、コードの可読性も向上します。


 let car = 'ludicrous car'; let myCar = `My ${car}`; let yourCar = `Your ${car}`; if (iHaveMoreThanOneCar) { myCar = `${myCar}s`; } if (youHaveMoreThanOneCar) { yourCar = `${youCar}s`; } 


 //  car  ,      (const) const car = 'ludicrous car'; let myCar = `My ${car}`; let yourCar = `Your ${car}`; if (iHaveMoreThanOneCar) { myCar = `${myCar}s`; } if (youHaveMoreThanOneCar) { yourCar = `${youCar}s`; } 

3)パイプのような演算子


RxJs使用する場合は、パイプのようなステートメントを使用します
パイプのような演算子には、インポート時に実行する必要があるコードのみが含まれます。

また、ファイル内の未使用のステートメントを見つけやすくなります。

注: Angular 5.5以降が必要です。


 import 'rxjs/add/operator/map'; import 'rxjs/add/operator/take'; iAmAnObservable .map(value => value.item) .take(1); 


 import { map, take } from 'rxjs/operators'; iAmAnObservable .pipe( map(value => value.item), take(1) ); 

4)テンプレートにサインインする


コンポーネントから監視対象オブジェクトをサブスクライブするのを避けます-代わりに、テンプレートから監視オブジェクトにサブスクライブします。

なんで?


asyncフィードは自動的に購読解除され、コードが簡素化され、手動の購読管理の必要がなくなります。 コンポーネントの偶発的なサブスクライブ解除のリスクも減少し、メモリリークが発生します。 これは、lintルールを使用して、符号なしの監視対象オブジェクトを検出することで修正可能です。

さらに、コンポーネントが静的なままになることを許可せず、データがサブスクリプション外で変更されたときにエラーを追加します。


 //  <p>{{ textToDisplay }}</p> //  iAmAnObservable .pipe( map(value => value.item), takeUntil(this._destroyed$) ) .subscribe(item => this.textToDisplay = item); 


 //  <p>{{ textToDisplay$ | async }}</p> //  this.textToDisplay$ = iAmAnObservable .pipe( map(value => value.item) ); 

5)サブスクリプションをクリアする


監視対象オブジェクトをサブスクライブするときは、必ずtaketakeUntilなどの演算子を使用して適切にサブスクライブを解除してください。

なんで?


監視対象オブジェクトのサブスクライブ解除によるエラーは、おそらくコンポーネントが削除された後、またはユーザーが別のページに移動したときにも監視対象ストリームが開いたままになるため、望ましくないメモリリークにつながります。

さらに、サブスクライブ解除のない観察可能なオブジェクトを検出するためのlintルールを作成します。


 iAmAnObservable .pipe( map(value => value.item) ) .subscribe(item => this.textToDisplay = item); 



 private _destroyed$ = new Subject(); public ngOnInit (): void { iAmAnObservable .pipe( map(value => value.item) //     iAmAnObservable   ,     / takeUntil(this._destroyed$) ) .subscribe(item => this.textToDisplay = item); } public ngOnDestroy (): void { this._destroyed$.next(); this._destroyed$.complete(); } 

別のtakeUntil対象オブジェクトが値を返すまで、 takeUntilを使用して変更をリッスンします。

 iAmAnObservable .pipe( map(value => value.item), take(1), takeUntil(this._destroyed$) ) .subscribe(item => this.textToDisplay = item); 

上記の例のtakeとともにtakeUntil使用していることに注意してください。 これにより、コンポーネントが削除される前にサブスクリプションに値が割り当てられなかったという事実に起因するメモリリークが回避されます。

takeUntilないtakeUntilサブスクリプションは最初の値を受け取るまで一時停止状態になりますが、コンポーネントが既に削除されているため、値を受け取ることはなく、メモリリークが発生します。

6)遅延読み込み


可能な限り、使用中のモジュールのみをAngularアプリケーションにロードしてください。

なんで?


これにより、ダウンロードしたアプリケーションのサイズが小さくなり、ロード時間が短縮されます。


 // app.routing.ts { path: 'not-lazy-loaded', component: NotLazyLoadedComponent } 


 // app.routing.ts { path: 'lazy-load', loadChildren: 'lazy-load.module#LazyLoadModule' } // lazy-load.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { LazyLoadComponent } from './lazy-load.component'; @NgModule({ imports: [ CommonModule, RouterModule.forChild([ { path: '', component: LazyLoadComponent } ]) ], declarations: [ LazyLoadComponent ] }) export class LazyModule {} 

次の記事で翻訳を続けました。 誰かが待ちたくない場合は、ここに元の記事へのリンクがあります。

Source: https://habr.com/ru/post/J447042/


All Articles