Angularのベストプラクティス

3つのフロントエンドフレームワークの1つとして、Angularフレームワークには独自の利点があり、効率的で複雑で洗練された単一ページアプリケーションを作成するために使用できます。この記事では、開発プロセスで参照するために、Angularの開発プロセスで推奨される18のベストプラクティスと例を紹介します。1. trackByWhat * ngForコマンドを使用して配列をHTMLで表示する場合、trackBy()関数を追加します。目的は、各アイテムに独立したidWhyを指定することです。通常の状況では、配列に変更があると、AngularはDOMツリーが再レンダリングされます。trackByメソッドが追加されると、Angularは特定の変更された要素を認識し、この特定の要素のDOMを更新してページのレンダリングパフォーマンスを向上させます。-> NetanelBasalExample【変更前】<li * ngFor =“アイテムのアイテムを削除; ”> {{Item}}コードをコピーします【After】//テンプレートに

//コンポーネント
trackByFn(index、item)で{
return item.id; //アイテムに対応する一意のID
}コードをコピーします2. constとletWhatが定数を宣言する場合は、letWhyaではなくconstを使用します。割り当ての意図をより明確にしますb。定数が再割り当てされると、コンパイラーは潜在的なリスクを回避するためにエラーを直接報告します。C。コードの可読性を高める例[前] let car = 'ludicrous car';
let myCar = My ${car};
let yourCar = Your ${car}; if (iHaveMoreThanOneCar) { myCar =KaTeX parse error:Expected 'EOF'、got位置12の '}':{myCar} s`;} ̲ if(youHaveMor… {youCar} s ; }复制代码【After】// 变量car不会被重赋值,所以用const声明 const car = 'ludicrous car'; let myCar =My $ {car} ; let yourCar =Your KaTeX parse error:Expected '}'、got 'EOF' at end of input:…){ myCar = ` {myCar} s ; } if (youHaveMoreThanOneCar) { yourCar =$ {youCar} s`;
}コードをコピーします3. RxJs演算子をパイプ可能演算子Whatと一緒に使用する場合は、パイプ可能演算子記号を使用します->さらに読むWhya。ツリーを振ることで最適化できます:インポートされたコードで、実行する必要のあるものだけを紹介しますb。コードで未使用の演算子を簡単に見つけることができます注:RxJsバージョン5.5以上が必要です例[前] import 'rxjs / add / operator / map';
import 'rxjs / add / operator / take';

iAmAnObservable
.map(value => value.item)
.take(1)复制代码【After】import {map、take} from 'rxjs / operators';

iAmAnObservable
.pipe(
map(value => value.item)、
take(1)
)コードをコピー4. API攻撃を隔離するすべてのAPIが安全であるとは限らない->多くの場合、APIと戦うために追加のコードロジックを追加する必要があるパッチは、ロジックをコンポーネントに配置するよりも優れています。別の場所にカプセル化することをお勧めします。たとえば、サービスにカプセル化してから、Wyaを別の場所で参照します。分離攻撃は、攻撃を元のリクエストの場所に近づけますb。攻撃パッチの処理に使用するコードを削減しますc。これらの攻撃を同じ場所にカプセル化し、見つけやすくしますd。バグを解決したい場合は、同じファイルで検索するだけでよいので、見つけやすくなります注: TODOタグと同様に、API修正をマークするために使用するAPI_FIXなどの独自のタグを作成できます。5.テンプレートのサブスクリプションts Whyaではなく、htmlサブスクリプションで変更するのに最適な方法。非同期パイプラインは自動的にサブスクライブを解除できます。サブスクリプション管理はコードを簡略化できますb。tsでサブスクリプションをキャンセルするのを忘れてメモリリークを引き起こすリスクを減らします(このリスクはlintルールの検出により回避できます)c。サブスクリプションの数を減らします 読み込み後にデータが変更され、バグが発生した場合例【変更前】//テンプレート

{{textToDisplay}}

//コンポーネント
iAmAnObservable
.pipe(
map(value => value.item)、
takeUntil(this._destroyed $)
).
subscribe(item => this.textToDisplay = item复制代码【After】//テンプレート

{{textToDisplay $ | 非同期}}

//コンポーネント
this.textToDisplay $ = iAmAnObservable
.pipe(
map(value => value.item)
)コードをコピーします6.サブスクリプションのクリーンアップobservableにサブスクライブする場合は、take、takeUntilなどの演算子を使用してサブスクリプションWhyaを適切にキャンセルしてください。キャンセルしない場合コンポーネントが破棄されたり、ユーザーが別のページに移動したりしても、サブスクリプションが発生する可能性がありますが、監視可能なストリームが常に維持され、メモリリークが発生することに注意してください。B。より良い方法は、例[前] iAmAnObservable
.pipe(
map(map(map(map( value => value.item)
).
subscribe(item => this.textToDisplay = item);コードをコピー[After] private _destroyed $ = new Subject();

public ngOnInit():void {
iAmAnObservable
.pipe(
map(value => value.item)
//破棄される前にリッスンし続けたい
takeUntil(this._destroyed $)
).
subscribe(item => this.textToDisplay = item);
}

public ngOnDestroy():void {
this._destroyed e バツ t ; t h s d e s t r y e d 。次(); this._destroyed .complete();
}コードをコピーする最初の値のみが必要な場合は、テイク(1)iAmAnObservable
.pipe(
map(value => value.item)、
take( 1)、
takeUntil(this._destroyed $)

.subscribe(item => this.textToDisplay = item);コードをコピーします注:ここでtakeUntilとtakeを同時に使用しています。目的は、コンポーネントが破棄される前に値を受信して​​いないため、メモリリークが発生しないようにすることです。(takeUntilがない場合、サブスクリプションは最初の値が取得されるまで存続します。コンポーネントが破棄された後、最初の値を受信できないため、メモリリークが発生します)7.適切な操作を使用します。何のために、適切なマージ演算子switchMapを選択します:古い値を新しく受信した値で置き換えたい場合mergeMap:すべての受信した値を同時に操作したい場合concatMap:受信した値を順番に処理したい場合exhaustMap :前の受信値を処理する場合は、後の値Whyaの処理をキャンセルします。チェーンで複数の演算子を使用する場合と比較して、適切な演算子を使用して同じ目的を達成すると、コード量を効果的に削減できますb。いいえ演算子を適切に使用すると、異なる演算子によって達成される効果が異なるため、予期しない動作が発生する可能性があります8.遅延読み込み条件が許せば、角度のあるアプリケーションで遅延読み込みモジュールを試してください。遅延読み込みとは、必要な場合にのみモジュールコンテンツを読み込むことです。理由:読み込む必要のあるアプリケーションの量を効果的に減らします。B。不要なモジュールの読み込みを回避することで、起動パフォーマンスを効果的に向上できます。例【変更前】{パス: 'not-lazy-ロードされた '、コンポーネント:NotLazyLoadedComponent}【変更後】// app.routing.ts

{
パス: 'lazy-load'、
loadChildren:()=> import(lazy-load.module).then(m => m.LazyLoadModule)
}

// lazy-load.module.ts
import {NgModule} from '@ angular / core';
'@ angular / common'から{CommonModule}をインポートします。
'@ angular / router'から{RouterModule}をインポートします。
'./lazy-load.component'から{LazyLoadComponent}をインポートします。

@NgModule({
imports:[
CommonModule、
RouterModule.forChild([
{
path: ''、
component:LazyLoadComponent
}
]))

宣言:[
LazyLoadComponent
]
})
エクスポートクラスLazyModule {}コピーコード9.サブスクリプションのネストを避ける場合によっては、特定の目的を達成するために複数のオブザーバブルからデータを取得する必要があります。この場合、サブスクリプションブロック内でサブスクリプションをネストしないでください。より適切な方法は、適切なチェーン演算子を使用することです。例:withLatestFrom、combineLatestなど。コードの匂い/読みやすさ/複雑さの理由:RxJを完全に使用していないため、開発者がRxJs APIコードのパフォーマンスの浅い使用に慣れていないことを示します:コールドオブザーバブルの場合、最初のオブザーバブルを引き続きサブスクライブします。それが完了するまでは、2番目のオブザーバブルの作業を開始します。ネットワークリクエストがある場合、パフォーマンスはウォーターフォールの例になります[Before] firstObservable KaTeX解析エラー:予期された '}'、入力の最後に 'EOF'があります:econdObservable .pipe(take(1)).subscribe (secondValue => {console.log(Combined values are: ${firstValue} &${secondValue}); });});【After】firstObservable p p e w t h L a t e s t F r メートル s e c d b s e r v a b l e .pipe(withLatestFrom(secondObservable )に示すように、第1()).subscribe(([firstValue、 secondValue])=> {console.log(Combined values are: ${firstValue} & ${secondValue});}); 10. anyの使用を避け、タイプWhatを明示的に定義する変数または定数を宣言する場合は、anyWhyaを使用するのではなく、特定のタイプを指定します。TSで未指定のタイプを宣言する場合変数またはファクトリでは、型は割り当てられた値から推測され、予期しない問題を引き起こす可能性があります。典型的な例は次のとおりです:例[前] const x = 1; const y = 'a'; const z = x + y; console.log(Value of z is: ${z}// zの出力値は1aです。元の予期された入力がyでもある場合、数値型でも予期しない問題が発生します。[後]これらの問題は、宣言された変数に適切な型を指定することで回避できます:const x:number = 1; const y:number = 'a'; const z:number = x + y; //この入力により、コンパイルエラーが発生すると、タイプ「 "a"」はタイプ 'number'に割り当てられません。Consy:number上記の方法により、タイプの欠落によるバグを回避できます。タイプを指定するもう1つの利点は、リファクタリングが容易になることです。より安全な例【変更前】public ngOnInit():void {let myFlashObject = {name: 'My cool name'、age: 'My cool age'、loc: 'My cool location'} this.processObject(myFlashObject);} public processObject(myObject:any):void {console.log(Name: ${myObject.name}); console.log(Age: ${myObject.age}); console.log(Location: ${myObject.loc});)//出力名:My cool nameAge:My cool ageLocation:My cool location myFlashObject内のloc属性の名前を変更したい場合locationpublic ngOnInit():void {let myFlashObject = {name: 'My cool name'、age : 'My cool age'、location: 'My cool location'} this.processObject(myFlashObject);} public processObject(myObject:any):void {console.log(Name: ${myObject.name}); console.log(Age: ${myObject.age}); console.log(Location: ${myObject.loc});} //出力名:My cool nameAge:My cool ageLocation:undefined myFlashObjectにタイプが指定されていない場合、myFlashObjectにメソッドのloc属性が存在しないようですが、属性[After]の値が間違っているために、上記の結果が正しく表示されません。 MyFlashObjectはタイプ定義を追加します。次のように、より明確なコンパイルエラーの問題が発生しますtype FlashObject = {name:string、age:string、location:string} public ngOnInit():void {let myFlashObject:FlashObject = {name: '私のクールな名前 '、age:'私のクールな年齢 '、//コンパイルエラーType' {name:string; age:string; loc:string;} 'typeに代入できません' FlashObjectType 'オブジェクトリテラルは既知のプロパティのみを指定できます、および「loc」はタイプ「FlashObjectType」に存在しません。loc: 'My cool location'} this.processObject(myFlashObject);} public processObject(myObject:FlashObject):void {console.log(Name: ${myObject.name}); console.log(Age: ${myObject.age})//コンパイルエラープロパティ 'loc'はタイプ 'FlashObjectType'に存在しません。Console.log(Location: ${myObject.loc});}まったく新しいプロジェクトを開始する場合は、tsconfig.jsonファイルでstrict:trueモードを設定して、strictモードをオンにし、すべてのstrictタイプチェックオプションをオンにすることをお勧めします11. lintルールを使用しますWhatlintルールは複数のプリセットで構成されますno-any、no-magic-numbers、no-consleなどのオプションを使用すると、tslint.jsonファイルで特定の検証ルールをオンにできます。lintルールを使用すると、どこにも生成されないはずです。動作が発生すると、より明確なエラーが表示されます。これにより、アプリケーションコードの一貫性と可読性が向上します。一部のlintルールには、このlintタスクを解決するための特定の修正ソリューションさえあります。独自のタスクを定義する場合lintルールの場合、TSQueryを使用して独自のlintルールを作成する古典的な例を書くこともできます。古典的な例は次のとおりです。例[前] public ngOnInit():void {console.log( 'I am naughty console log message') ; console.warn( 'いたずらなコンソール警告メッセージです'); console.error( 'いたずらなコンソールエラーメッセージです');} //出力はエラーを報告していませんが、制御されています 次の情報が出力されます:いたずらなコンソールメッセージですいたずらなコンソール警告メッセージですいたずらなコンソールエラーメッセージです[後] // tslint.json {“ rules”:{…“ no-console”:[true、“ log” 、// console.logは許可されない“ warn” // console.warnは許可されない]}} //…component.tspublic ngOnInit():void {console。log( 'いたずらなコンソールログメッセージ'); console.warn( 'いたずらなコンソール警告メッセージ'); console.error( 'いたずらなコンソールエラーメッセージ');} //出力リンクはコンソールにあります。エラーはlogおよびlog.warnステートメントで報告され、console.logへの呼び出しは許可されないため、console.errorは報告されません。console.warnへの呼び出しは許可されません。再利用可能なコンポーネント再利用可能なコードスニペットをコンポーネントから新しいコンポーネントに抽出して、コンポーネントを可能な限り「ダム」にして、より多くのシナリオで再利用して「ダム」コンポーネントを書き込むことができるということは、非表示がないことを意味します特別なロジックが含まれます。操作は、一般的な規則として提供される入力と出力に単純に依存します。コンポーネントツリーで最も子ノードが多いコンポーネントは、最も「ダム」なものになります。コードの反復率を下げると、ダムコンポーネントの保守と変更が簡単になり、バグの可能性も低くなります。ダムコンポーネントを使用すると、一般的なコンポーネントAPIを抽出する方法を慎重に検討し、混合問題を特定することができます。13.コンポーネントは表示ロジックのみを処理します。表示ロジック以外のビジネスロジックをコンポーネントにカプセル化しないようにし、コンポーネントが表示ロジックの処理にのみ使用されるようにします。理由:コンポーネントは、ビューと表示の目的を制御するように設計されています。ビジネスロジックは独自の適切なメソッドまたはサービスにカプセル化し、ビジネスロジックはコンポーネントロジックから分離する必要があります。B。ビジネスロジックがサービスに抽出される場合、通常はより多くなります。ユニットテストの使用に適しており、同じビジネスロジックを必要とする他のコンポーネントで再利用できます。14.長いメソッドを回避する長いメソッドは通常、すでに多くのタスクが含まれていることを示しているため、単一責任の原則を使用してみます。1つのメソッドは全体として完了する必要があります。 1つ目は、複数の操作がある場合、これらのメソッドを抽出して独立した関数を形成し、それらがその責任を単独で担当するようにし、それらをWhyaと呼ぶことです。長い方法は、読み取り、理解、維持が困難です。それらのいくつかを変更するとメソッド内の他のロジックに影響を与える可能性があるため、バグが発生しやすくなります。これにより、コードのリファクタリングがさらに難しくなります。B。メソッドは循環的複雑度によって測定できます。循環的複雑度を検出するためのTSLintメソッドがいくつかあります。プロジェクトでそれらを使用して、バグを回避し、コードの可用性を検出できます。15. DryWhatDry =コードウェアハウスに重複したコードがないことを保証しないでください。重複したコードを抽出し、それを使用する必要がある場所を参照してください。理由:複数の場所で重複したコードを使用すると、コードロジックを変更したい場合に、複数の場所で変更し、コードの保守性を低下させると、コードロジックに変更を加えることが難しくなり、テストプロセスが非常に長くなります。b。重複したコードを1か所に抽出すると、変更する必要があるコードは1つだけで、1つのテストのみが実行されますc 。同時に、コードが少ないほど速度が速くなります16.キャッシュを増やすAPIリクエストを開始するための応答は通常あまり変更されません。このようなシナリオでは、キャッシュメカニズムを増やして、取得した値を同じAPIリクエストとして保存できます。再起動するときに、キャッシュにすでに値があるかどうかを確認します。ある場合は、直接使用できます。それ以外の場合は リクエストとキャッシュを開始します。これらの値が変化するが、頻繁に変化しない場合は、キャッシュを使用するか、再度呼び出すかを決定するために、キャッシュ時間を導入できます。キャッシュメカニズムがある理由は、不必要なAPI呼び出しを回避できるため、繰り返しの呼び出しを回避することでアプリケーションの改善に役立ちます。応答性が向上し、ネットワークが戻るのを待つ必要がなくなり、同じ情報を繰り返しダウンロードする必要がなくなりました。17。テンプレート内のロジックを避けます。HTMLにロジックを追加する必要がある場合は、単純な&&であっても、それを抽出することをお勧めします。コンポーネント内のWhyテンプレートのロジックは単体テストが困難です。テンプレートコードを切り替えると、コードの問題が発生しやすくなります[以前] //テンプレート<p * ngIf = "role === developer '">ステータス:Developer DryWhatDry =自分自身を繰り返さないで、コードウェアハウスに重複コードがないことを確認し、重複コードを抽出して、必要な場所で参照してください。理由:複数の場所で重複コードを使用すると、コードロジックを変更したい場合に、複数の場所で変更する必要があるため、コードの保守性が低下し、コードロジックの変更が困難になり、テストプロセスが非常に長くなります。B。重複するコードを1か所に抽出すると、変更する必要があるコードは1つだけで、1回で済みます。テストc。同時に、コードが少ないほど速度が速くなります。16.キャッシュを増やします。APIリクエストの応答を開始したものは通常変更されないことが多いため、このようなシナリオでは、キャッシュメカニズムを増やし、取得した値を同じように保存できます。 API要求が再開始されたら、キャッシュに値が既に存在するかどうかを確認します。存在する場合は、それを直接使用できます。それ以外の場合は、要求が開始されてキャッシュされます。これらの値が変化するが、頻繁に変化しない場合は、キャッシュを使用するか、再度呼び出すかを決定するために、キャッシュ時間を導入できます。キャッシュメカニズムがある理由は、不必要なAPI呼び出しを回避できるため、繰り返しの呼び出しを回避することでアプリケーションの改善に役立ちます。応答性が向上し、ネットワークが戻るのを待つ必要がなくなり、同じ情報を繰り返しダウンロードする必要がなくなりました。17。テンプレート内のロジックを避けます。HTMLにロジックを追加する必要がある場合は、単純な&&であっても、それを抽出することをお勧めします。コンポーネント内のWhyテンプレートのロジックは単体テストが困難です。テンプレートコードを切り替えると、コードの問題が発生しやすくなります[以前] //テンプレート<p * ngIf = "role === developer '">ステータス:Developer DryWhatDry =自分自身を繰り返さないで、コードウェアハウスに重複コードがないことを確認し、重複コードを抽出して、必要な場所で参照してください。理由:複数の場所で重複コードを使用すると、コードロジックを変更したい場合に、複数の場所で変更する必要があるため、コードの保守性が低下し、コードロジックの変更が困難になり、テストプロセスが非常に長くなります。B。重複するコードを1か所に抽出すると、変更する必要があるコードは1つだけで、1回で済みます。テストc。同時に、コードが少ないほど速度が速くなります。16.キャッシュを増やします。APIリクエストの応答を開始したものは通常変更されないことが多いため、このようなシナリオでは、キャッシュメカニズムを増やし、取得した値を同じように保存できます。 API要求が再開始されたら、キャッシュに値が既に存在するかどうかを確認します。存在する場合は、それを直接使用できます。それ以外の場合は、要求が開始されてキャッシュされます。これらの値が変化するが、頻繁に変化しない場合は、キャッシュを使用するか、再度呼び出すかを決定するために、キャッシュ時間を導入できます。キャッシュメカニズムがある理由は、不必要なAPI呼び出しを回避できるため、繰り返しの呼び出しを回避することでアプリケーションの改善に役立ちます。応答性が向上し、ネットワークが戻るのを待つ必要がなくなり、同じ情報を繰り返しダウンロードする必要がなくなりました。17。テンプレート内のロジックを避けます。HTMLにロジックを追加する必要がある場合は、単純な&&であっても、それを抽出することをお勧めします。コンポーネント内のWhyテンプレートのロジックは単体テストが困難です。テンプレートコードを切り替えると、コードの問題が発生しやすくなります[以前] //テンプレート<p * ngIf = "role === developer '">ステータス:Developer キャッシュの追加通常、API要求に対する応答は頻繁に変更されません。このようなシナリオでは、キャッシュメカニズムを増やして、取得した値を保存できます。同じAPI要求が再度開始されたら、キャッシュにすでに値があるかどうかを確認します。はいの場合は直接使用できます。それ以外の場合は、要求とキャッシュが開始されます。これらの値が変化するが、頻繁に変化しない場合は、キャッシュを使用するか、再度呼び出すかを決定するために、キャッシュ時間を導入できます。キャッシュメカニズムがある理由は、不必要なAPI呼び出しを回避できるため、繰り返しの呼び出しを回避することでアプリケーションの改善に役立ちます。応答性が向上し、ネットワークが戻るのを待つ必要がなくなり、同じ情報を繰り返しダウンロードする必要がなくなりました。17。テンプレート内のロジックを避けます。HTMLにロジックを追加する必要がある場合は、単純な&&であっても、それを抽出することをお勧めします。コンポーネント内のWhyテンプレートのロジックは単体テストが困難です。テンプレートコードを切り替えると、コードの問題が発生しやすくなります[以前] //テンプレート<p * ngIf = "role === developer '">ステータス:Developer キャッシュの追加通常、API要求に対する応答は頻繁に変更されません。このようなシナリオでは、キャッシュメカニズムを増やして、取得した値を保存できます。同じAPI要求が再度開始されたら、キャッシュにすでに値があるかどうかを確認します。はいの場合は直接使用できます。それ以外の場合は、要求とキャッシュが開始されます。これらの値が変化するが、頻繁に変化しない場合は、キャッシュを使用するか、再度呼び出すかを決定するために、キャッシュ時間を導入できます。キャッシュメカニズムがある理由は、不必要なAPI呼び出しを回避できるため、繰り返しの呼び出しを回避することでアプリケーションの改善に役立ちます。応答性が向上し、ネットワークが戻るのを待つ必要がなくなり、同じ情報を繰り返しダウンロードする必要がなくなりました。17。テンプレート内のロジックを避けます。HTMLにロジックを追加する必要がある場合は、単純な&&であっても、それを抽出することをお勧めします。コンポーネント内のWhyテンプレートのロジックは単体テストが困難です。テンプレートコードを切り替えると、コードの問題が発生しやすくなります[以前] //テンプレート<p * ngIf = "role === developer '">ステータス:Developer

// componentpublic ngOnInit():void {th​​is.role = 'developer';}【変更後】<p * ngIf =“ showDeveloperStatus”>ステータス:Developer // componentpublic ngOnInit():void {th​​is.role = 'developer'; this.showDeveloperStatus = true;} 18.文字列型を安全に宣言する何か特定の値のみを持つ文字列変数がある場合、それを文字列型として宣言するよりも、可能な値のコレクション型として宣言する方が良いです。変数の適切な宣言を提供することで、バグの回避に役立ちます。コードの記述が期待を超える場合、実行前にprivate myStringValue:stringを見つけるのを待つのではなく、コンパイル段階で見つけることができます。

if(itShouldHaveFirstValue){
myStringValue = 'First';
} else {
myStringValue = 'Second'
}复制代码【After】private myStringValue: 'First' | 'セカンド';

if(itShouldHaveFirstValue){
myStringValue = 'First';
} else {
myStringValue = 'Other'
}

//これにより、以下のエラーが発生します。
タイプ「“ Other”」はタイプ「“ First”に割り当てられません| “ Second” '
(プロパティ)AppComponent.myValue:“ First” | 「セカンド」

元の記事を28件公開 Likes0 訪問数907

おすすめ

転載: blog.csdn.net/srhgsr/article/details/105498961