Melhor experiência na criação de aplicativos angulares limpos e rápidos

Para escrever este artigo, eles foram incentivados pela pesquisa de desenvolvedores de front-end JavaScript em sua empresa em Stavropol. Porque Por um longo tempo, não foi possível encontrar um programador inteligente e, então, decidimos lançar um programa de estágio com muito material de treinamento em Angular & JS.

Esta é uma tradução de um artigo de Vamsi Vempati sobre sua experiência com um aplicativo de larga escala para o Trade Me escrito em Angular.



Até o momento, já trabalhei alguns anos em um aplicativo Angular em larga escala na Trade Me. Nos últimos anos, nossa equipe aprimorou nosso aplicativo em termos de padrões e desempenho de escrita de código para trazê-lo ao melhor estado possível.

O artigo descreve os métodos que usamos em nosso projeto. O texto está associado principalmente a Angular, TypeScript, RxJs e @ ngrx / store.

Além disso, serão consideradas algumas diretrizes gerais para escrever código que ajudarão a tornar o aplicativo mais "limpo" e legível.

1) trackBy


Ao usar ngFor para fazer um loop em uma matriz em modelos, consulte a função trackBy , que retornará um identificador exclusivo para cada elemento.

Porque


Quando a matriz é alterada, o Angular redesenha completamente a árvore do DOM. Mas se você usar a função trackBy , o Angular entenderá qual elemento foi alterado e fará alterações no DOM apenas para esse elemento específico.

Nota: uma descrição mais detalhada pode ser encontrada no artigo de Nathanel Bazal. [eng]

Para


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


Depois


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

2) const ou let?


Ao declarar variáveis, use const se elas não serão reatribuídas.

Porque


O uso de let e const, quando apropriado, torna o motivo da declaração de variáveis ​​mais compreensível. Também pode ajudar a identificar problemas quando um valor é reatribuído aleatoriamente para uma constante devido a um erro em tempo de compilação. Também melhora a legibilidade do código.

Para


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

Depois


 //  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) Operadores semelhantes a tubos


Use instruções semelhantes a tubos ao trabalhar com RxJs .
Os operadores de pipe incluem apenas o código que precisa ser executado durante a importação.

Também facilita a localização de instruções não utilizadas nos arquivos.

Nota: Angular 5.5 e superior são necessários.

Para


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

Depois


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

4) Entre no modelo


Evite assinar objetos monitorados a partir de componentes - em vez disso, assine-os a partir de um modelo.

Porque


async feeds async são cancelados automaticamente, simplificando o código e eliminando a necessidade de gerenciamento manual de assinaturas. O risco de cancelamento acidental de inscrição em um componente também é reduzido, o que resultará em um vazamento de memória. Isso é corrigível usando a regra lint para detectar objetos observados não assinados.

Além disso, ele não permite que os componentes permaneçam estáticos e adiciona erros quando os dados são alterados fora da assinatura.

Para


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

Depois


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

5) Limpar assinaturas


Ao se inscrever nos objetos monitorados, sempre cancele a inscrição deles adequadamente, usando operadores como take , takeUntil etc.

Porque


Erros ao cancelar a inscrição de objetos observados levarão a um vazamento de memória indesejável, pois o fluxo observado permanece aberto, provavelmente mesmo após a remoção do componente ou quando o usuário se move para outra página.

Além disso, crie uma regra de lint para detectar objetos observáveis ​​dos quais não há cancelamentos de inscrição.

Para


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


Depois


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

Usando o takeUntil para escutar as alterações até que outro objeto observado retorne um valor:

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

Observe o uso de takeUntil junto com take no exemplo acima. Isso evita vazamentos de memória causados ​​pelo fato de que nenhum valor foi atribuído à assinatura antes da remoção do componente.

Sem takeUntil assinatura ainda estará em um estado suspenso, até receber seu primeiro valor, mas, como o componente já foi removido, ele nunca receberá o valor e isso levará a um vazamento de memória.

6) carregamento preguiçoso


Sempre que possível, tente carregar os módulos em um aplicativo Angular apenas quando estiverem em uso.

Porque


Isso reduzirá o tamanho do aplicativo baixado e diminuirá o tempo de carregamento.

Para


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

Depois


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

Tradução continuada no próximo artigo. Se alguém não quiser esperar, aqui está um link para o artigo original.

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


All Articles