22 tips untuk pengembang Angular. Bagian 1

Penulis artikel, bagian pertama dari terjemahan yang kami terbitkan, mengatakan bahwa ia telah mengerjakan aplikasi berskala besar di Trade Me selama sekitar dua tahun sekarang. Selama beberapa tahun terakhir, tim pengembangan aplikasi terus meningkatkan proyek, baik dari segi kualitas kode dan kinerja.


Seri materi ini akan fokus pada pendekatan pengembangan yang digunakan oleh tim Trade Me, yang dinyatakan dalam bentuk lebih dari dua lusin rekomendasi mengenai teknologi seperti Angular, TypeScript, RxJS dan @ ngrx / store. Selain itu, beberapa perhatian akan diberikan pada teknik pemrograman universal yang bertujuan membuat kode aplikasi lebih bersih dan lebih akurat.

1. Tentang trackBy


Menggunakan ngFor untuk melintasi array dalam template, gunakan konstruksi ini dengan fungsi trackBy , yang mengembalikan pengidentifikasi unik untuk setiap elemen.

▍ Penjelasan


Ketika array berubah, Angular merender seluruh pohon DOM. Tetapi jika Anda menggunakan trackBy , sistem akan tahu elemen mana yang telah berubah dan akan membuat perubahan pada DOM yang hanya berlaku untuk elemen tertentu. Detail tentang ini dapat ditemukan di sini .

▍To


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

FterSetelah itu


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

2. Kata kunci const dan let


Jika Anda akan mendeklarasikan variabel yang nilainya tidak Anda rencanakan untuk diubah, gunakan kata kunci const .

▍ Penjelasan


Penggunaan yang tepat dari kata kunci let dan const mengklarifikasi maksud mengenai penggunaan entitas yang dinyatakan menggunakannya. Selain itu, pendekatan ini membuatnya lebih mudah untuk mengenali masalah yang disebabkan oleh nilai konstan yang ditimpa secara tidak sengaja. Dalam situasi ini, kesalahan kompilasi dilemparkan. Selain itu, ini meningkatkan keterbacaan kode.

▍To


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

FterSetelah itu


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

3. operator konveyor


Saat bekerja dengan RxJS, gunakan operator pipelined.

▍ Penjelasan


Operator yang disampaikan mendukung algoritma pohon-goyang, yaitu, ketika mereka diimpor, hanya kode yang direncanakan akan dieksekusi akan dimasukkan dalam proyek. Ini juga memudahkan untuk mengidentifikasi pernyataan yang tidak digunakan dalam file.

Harap dicatat bahwa rekomendasi ini relevan untuk Angular versi 5.5 dan lebih tinggi.

▍To


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

FterSetelah itu


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

4. Isolasi perbaikan API


Tidak semua API sepenuhnya stabil dan bebas kesalahan. Oleh karena itu, kadang-kadang perlu untuk memperkenalkan beberapa logika ke dalam kode yang ditujukan untuk memperbaiki masalah API. Alih-alih menempatkan logika ini dalam komponen di mana API yang ditambal digunakan, akan lebih baik untuk mengisolasinya di suatu tempat, misalnya, dalam layanan, dan merujuk dari komponen tidak lagi ke API yang bermasalah, tetapi ke layanan yang sesuai.

▍ Penjelasan


Pendekatan yang diusulkan memungkinkan menjaga koreksi "lebih dekat" ke API, yaitu, sedekat mungkin dengan kode dari mana permintaan jaringan dibuat mungkin. Akibatnya, jumlah kode aplikasi yang berinteraksi dengan API yang bermasalah berkurang. Selain itu, ternyata semua koreksi ada di satu tempat, akibatnya akan lebih mudah untuk bekerja dengannya. Jika Anda harus memperbaiki kesalahan di API, maka jauh lebih mudah untuk melakukan ini dalam satu file daripada menyebarkan koreksi ini di seluruh aplikasi. Ini memfasilitasi tidak hanya penciptaan koreksi, tetapi juga pencarian kode yang sesuai dalam proyek, dan dukungannya.

Selain itu, Anda dapat membuat tag Anda sendiri, seperti API_FIX (yang menyerupai tag TODO ), dan menandai perbaikan dengan mereka. Ini membuatnya lebih mudah untuk menemukan perbaikan seperti itu.

5. Berlangganan dalam template


Hindari berlangganan yang dapat diobservasi dari komponen. Sebagai gantinya, berlanggananlah dalam templat.

▍ Penjelasan


Operator pipeline asinkron secara otomatis berhenti berlangganan sendiri, yang menyederhanakan kode, menghilangkan kebutuhan untuk manajemen berlangganan manual. Ini, di samping itu, mengurangi risiko bahwa pengembang akan lupa berhenti berlangganan dari komponen, yang dapat menyebabkan kebocoran memori. Dimungkinkan untuk mengurangi kemungkinan kebocoran memori dengan menggunakan aturan linter yang bertujuan mengidentifikasi objek yang dapat diamati yang tidak mereka hentikan berlangganan.

Selain itu, penerapan pendekatan ini mengarah pada fakta bahwa komponen berhenti menjadi komponen stateful, yang dapat menyebabkan kesalahan ketika data berubah di luar langganan.

▍To


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

FterSetelah itu


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

6. Menghapus Langganan


Saat berlangganan ke objek yang dipantau, selalu pastikan bahwa langganan ke mereka dihapus dengan benar menggunakan operator seperti take , takeUntil dan sebagainya.

▍ Penjelasan


Jika Anda tidak berhenti berlangganan dari objek yang diamati, ini akan menyebabkan kebocoran memori, karena aliran objek yang diamati akan tetap terbuka, yang dimungkinkan bahkan setelah komponen dihancurkan atau setelah pengguna pergi ke halaman lain dari aplikasi.

Yang lebih baik lagi adalah membuat aturan linter untuk mendeteksi objek yang diamati dengan langganan yang valid.

▍To


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

FterSetelah itu


Gunakan operator takeUntil jika Anda ingin mengamati perubahan beberapa objek hingga objek lain yang diamati menghasilkan nilai tertentu:

 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(); } 

Menggunakan sesuatu seperti this adalah pola yang digunakan untuk mengontrol penghapusan langganan ke banyak objek yang diamati dalam suatu komponen.

Gunakan take jika Anda hanya perlu nilai pertama yang dikembalikan oleh objek yang diamati:

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

Harap perhatikan bahwa di sini kami menggunakan takeUntil dengan take . Hal ini dilakukan untuk menghindari kebocoran memori yang disebabkan oleh fakta bahwa langganan tidak mengarah pada memperoleh nilai sampai komponen dihancurkan. Jika fungsi takeUntil tidak digunakan di takeUntil , berlangganan akan ada sampai nilai pertama diterima, tetapi karena komponen sudah dihancurkan, nilai ini tidak akan pernah diterima, yang akan menyebabkan kebocoran memori.

7. Menggunakan operator yang sesuai


Menggunakan operator perataan dengan objek yang dapat diamati, terapkan yang sesuai dengan fitur dari masalah yang sedang dipecahkan.

  • Gunakan switchMap ketika Anda perlu mengabaikan tindakan terjadwal sebelumnya ketika tindakan baru tiba.
  • Gunakan mergeMap jika Anda perlu memproses semua tindakan yang dikirim secara paralel.
  • Gunakan concatMap ketika tindakan perlu diproses satu demi satu, sesuai urutan diterima.
  • Gunakan exhaustMap dalam situasi di mana, dalam proses pemrosesan tindakan yang diterima sebelumnya, Anda perlu mengabaikan yang baru.

Detail tentang ini dapat ditemukan di sini .

▍ Penjelasan


Jika mungkin, menggunakan satu operator, alih-alih mencapai efek yang sama dengan menggabungkan beberapa operator dalam satu rantai, mengurangi jumlah kode aplikasi yang perlu dikirim ke pengguna. Menggunakan operator yang dipilih secara tidak tepat dapat menyebabkan perilaku program yang salah, karena berbagai operator memproses objek secara berbeda.

8. Memuat malas


Kemudian, jika memungkinkan, cobalah untuk mengatur pemuatan modul-modul aplikasi Angular yang malas. Teknik ini bermuara pada fakta bahwa sesuatu dimuat hanya jika digunakan. Misalnya, komponen dimuat hanya ketika perlu ditampilkan.

▍ Penjelasan


Pemuatan malas mengurangi ukuran materi aplikasi yang harus diunduh pengguna. Ini dapat meningkatkan kecepatan pengunduhan aplikasi karena fakta bahwa modul yang tidak digunakan tidak ditransfer dari server ke klien.

▍To


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

FterSetelah itu


 // 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 {} 

9. Tentang langganan dalam langganan lain


Terkadang, untuk melakukan beberapa tindakan, Anda mungkin memerlukan data dari beberapa objek yang dapat diamati. Dalam situasi seperti itu, hindari membuat langganan ke objek tersebut di dalam blok subscribe objek yang dapat diamati lainnya. Alih-alih, gunakan operator yang sesuai untuk memadukan perintah. Di antara operator tersebut, seseorang dapat mencatat dengan withLatestFrom dan combineLatest . Pertimbangkan contoh-contohnya, dan berikan komentar.

▍To


 firstObservable$.pipe(  take(1) ) .subscribe(firstValue => {   secondObservable$.pipe(       take(1)   )   .subscribe(secondValue => {       console.log(`Combined values are: ${firstValue} & ${secondValue}`);   }); }); 

FterSetelah itu


 firstObservable$.pipe(   withLatestFrom(secondObservable$),   first() ) .subscribe(([firstValue, secondValue]) => {   console.log(`Combined values are: ${firstValue} & ${secondValue}`); }); 

▍ Penjelasan


Jika kita berbicara tentang keterbacaan, tentang kompleksitas kode, atau tentang tanda-tanda kode yang buruk, maka ketika program tidak menggunakan fitur RxJS secara penuh, ini berarti bahwa pengembang tidak terbiasa dengan API RxJS. Jika kita menyentuh topik kinerja, ternyata jika objek yang diamati memerlukan waktu untuk diinisialisasi, maka ia akan berlangganan firstObservable , maka sistem akan menunggu operasi selesai, dan hanya setelah itu pekerjaan dengan objek yang diamati kedua akan dimulai. Jika objek ini adalah permintaan jaringan, maka itu akan terlihat seperti eksekusi permintaan yang sinkron.

10. Tentang mengetik


Selalu berusaha mendeklarasikan variabel atau konstanta dengan tipe selain any .

▍ Penjelasan


Jika variabel atau konstanta dideklarasikan dalam TypeScript tanpa menentukan tipe, tipe akan disimpulkan berdasarkan nilai yang diberikan padanya. Ini bisa menimbulkan masalah. Pertimbangkan contoh klasik perilaku sistem dalam situasi yang serupa:

 const x = 1; const y = 'a'; const z = x + y; console.log(`Value of z is: ${z}` //  Value of z is 1a 

Diasumsikan bahwa y adalah angka di sini, tetapi program kami tidak mengetahuinya, sehingga ia menampilkan sesuatu yang terlihat salah, tetapi tidak menghasilkan pesan kesalahan apa pun. Masalah serupa dapat dihindari dengan menetapkan tipe yang sesuai untuk variabel dan konstanta.

Kami menulis ulang contoh di atas:

 const x: number = 1; const y: number = 'a'; const z: number = x + y; //    : Type '"a"' is not assignable to type 'number'. const y:number 

Ini membantu untuk menghindari kesalahan tipe data.

Keuntungan lain dari pendekatan sistematis untuk mengetik adalah menyederhanakan refactoring dan mengurangi kemungkinan kesalahan selama proses ini.

Pertimbangkan sebuah contoh:

 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}`); } //  Name: My cool name Age: My cool age Location: My cool location 

Misalkan kita ingin mengubah, di myFlashObject , nama properti loc ke location dan membuat kesalahan myFlashObject mengedit kode:

 public 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}`); } //  Name: My cool name Age: My cool age Location: undefined 

Jika mengetik tidak digunakan saat membuat objek myFlashObject , dalam kasus kami, sistem mengasumsikan bahwa nilai properti loc dari myFlashObject tidak undefined . Dia tidak berpikir bahwa loc mungkin nama properti yang tidak valid.

Jika mengetik digunakan ketika menggambarkan objek myFlashObject , maka dalam situasi yang sama kita akan melihat, ketika menyusun kode, pesan kesalahan yang luar biasa:

 type FlashObject = {   name: string,   age: string,   location: string } public ngOnInit (): void {   let myFlashObject: FlashObject = {       name: 'My cool name',       age: 'My cool age',       //         Type '{ name: string; age: string; loc: string; }' is not assignable to type 'FlashObjectType'.       Object literal may only specify known properties, and 'loc' does not exist in type 'FlashObjectType'.       loc: 'My cool location'   }   this.processObject(myFlashObject); } public processObject(myObject: FlashObject): void {   console.log(`Name: ${myObject.name}`);   console.log(`Age: ${myObject.age}`)   //     Property 'loc' does not exist on type 'FlashObjectType'.   console.log(`Location: ${myObject.loc}`); } 

Jika Anda mulai bekerja pada proyek baru, akan berguna untuk mengatur, dalam file tsconfig.json , opsi strict:true untuk memungkinkan pemeriksaan tipe yang ketat.

11. Tentang penggunaan linter


Tslint memiliki berbagai aturan standar seperti no-any , no-magic-number , no-console . Linter dapat dikustomisasi dengan mengedit file tslint.json untuk mengatur verifikasi kode sesuai dengan aturan tertentu.

▍ Penjelasan


Menggunakan linter untuk memeriksa kode berarti bahwa jika sesuatu muncul dalam kode yang dilarang oleh aturan, Anda akan menerima pesan kesalahan. Ini berkontribusi pada keseragaman kode proyek, meningkatkan keterbacaannya. Lihat aturan tslint lainnya di sini.

Perlu dicatat bahwa beberapa aturan termasuk cara mengoreksi apa yang dianggap tidak dapat diterima sesuai dengan mereka. Jika perlu, Anda bisa membuat aturan sendiri. Jika Anda tertarik, lihat materi ini , yang membahas pembuatan aturan khusus untuk linter menggunakan TSQuery .

▍To


 public ngOnInit (): void {   console.log('I am a naughty console log message');   console.warn('I am a naughty console warning message');   console.error('I am a naughty console error message'); } // .    ,    : I am a naughty console message I am a naughty console warning message I am a naughty console error message 

FterSetelah itu


 // tslint.json {   "rules": {       .......       "no-console": [            true,            "log", //  console.log             "warn" //  console.warn        ]  } } // ..component.ts public ngOnInit (): void {   console.log('I am a naughty console log message');   console.warn('I am a naughty console warning message');   console.error('I am a naughty console error message'); } // .      console.log and console.warn        console.error,         Calls to 'console.log' are not allowed. Calls to 'console.warn' are not allowed. 

Ringkasan


Hari ini kami meninjau 11 rekomendasi yang kami harap akan bermanfaat bagi pengembang Angular. Lain kali, tunggu 11 tips lagi.

Pembaca yang budiman! Apakah Anda menggunakan kerangka kerja Sudut untuk mengembangkan proyek web?

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


All Articles