От автора: в этой статье мы покажем некоторые приемы, которые можно использовать в Angular, чтобы сделать код более чистым и улучшить производительность приложения.
Недавно я завершил проект на Angular и по ходу я узнал некоторые вещи, которые могли бы пригодиться другим разработчикам. Итак, если вам нужны полезные для работы с Angular уроки, или вы просто ищете лучший способ управлять своими проектами Angular, вот несколько советов и рекомендаций, которые, возможно, пригодятся вам в процессе.
1. Отмените подписку на observable RxJS
Каждый раз, когда компонент или директива уничтожается, подписка на observable остается активной. Поэтому важно отказаться от подписки на него, чтобы освободить память в системе. Есть много способов сделать это, но я предпочитаю использовать функцию takeUntil:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import { Component, OnDestroy, OnInit } from "@angular/core"; import { Observable, Subject, interval } from "rxjs"; import { takeUntil } from "rxjs/operators"; @Component({ selector: "app-test", template: `<div>Test</div>` }) export class TestComponent implements OnDestroy, OnInit { private destroyed$ = new Subject<void>(); private ticks$ = interval(1000); public ngOnInit() { this.ticks$ .pipe(takeUntil(this.destroyed$)) .subscribe(data => console.log(data)); } public ngOnDestroy() { this.destroyed$.next(); this.destroyed$.complete(); } } |
Если вам нравятся декораторы, вы можете рассмотреть этот пакет, который предоставляет декларативный способ отмены подписки на observable при уничтожении компонента: //github.com/NetanelBasal/ngx-take-until-destroy
PS: Вам не нужно беспокоиться об отмене подписки, если вы используете AsyncPipe, потому что она отписывается автоматически. Кроме того, методы, кроме take(n), takeWhile(predicate), first() и first(predicate) отписываются сами.
2. Создайте более элегантный импорт с помощью алиасов typescript
Когда кодовая база начинает разрастаться, вы можете встретиться, например, с таким импортом:
1 |
import { MyComponent } from '../../../../../../shared/components/mycomponent' |
Это очень раздражает, потому что вы не знаете, сколько точно точек-точек-слэш вам нужно написать. Фактически, компилятор TypeScript позволяет использовать сопоставление маршрутов, поэтому мы можем импортировать файлы следующим образом:
1 |
import { MyComponent } from '@shared/components/mycomponent' |
Все, что нам нужно сделать, это определить пути и свойства baseUrl в разделе compilerOptions в файле tsconfig.json. Важно знать, что все пути обрабатываются относительно baseUrl. Пример:
1 2 3 4 5 6 7 8 9 10 11 |
{ "compilerOptions": { ... "baseUrl": "./src", "paths": { "@shared/*":["app/modules/shared/*"], "@core/*":["app/modules/core/*"] } ... } } |
3. Используйте trackBy в *ngFor
Когда мы используем директиву *ngFor, изменения DOM отслеживаются идентификатором объекта. Это подходит для большинства ситуаций, но с введением немутационных практик и Redux мы получаем каждый раз новые объекты. Это означает, что каждый раз *ngFor отображает список в DOM, но мы знаем, что операции DOM очень затратны.
Когда мы используем trackBy с *ngFor, он начинает распространение изменений, отслеживаемых данным идентификатором, а не идентификатором объекта. Пример:
1 2 3 4 5 |
<div *ngFor="let post of posts;trackBy:trackByFn"></div> ... identify(index,item){ return post.id; } |
4. Используйте интерфейсы вместо классов
Иногда нам нужны некоторые модели или определения для данных сервера. Интерфейсы могут использоваться для этой цели без дополнительных затрат при конечном выводе. В отличие от классов, интерфейсы полностью удаляются во время создания сборки, поэтому они не будут добавлять лишний код в финальный пакет.
5. Очистите все консоли
Во время разработки мы пишем много console.logs для отладки приложения, и иногда мы показываем некоторые сведения, которые не хотим, чтобы видели наши пользователи. Мы можем очень просто это удалить, используя несколько строк кода для рабочей сборки. Добавьте этот код в inmain.js:
1 2 3 4 5 6 7 8 |
import { environment } from './environments/environment'; if (environment.production) { // Удаление console.log в рабочей сборке window.console.log = () => { }; enableProdMode(); } |
6. Проинспектируйте пакет с помощью webpack-bundle-analyzer
Анализ пакета — это отличный способ улучшения производительности приложений. Визуализация вывода веб-пакета поможет вам понять состав пакета, посмотреть, какие модули занимают место и определить ненужные зависимости. Вот как выглядит визуализация:
Подробнее об этом инструменте вы можете прочитать здесь: //alligator.io/angular/bundle-size/
7. Не задавайте отложенную загрузку для маршрута по умолчанию
Отложенная загрузка модулей — это отличная функция, которая помогает сократить время запуска и загружать фрагменты кода по требованию. Нам не нужно загружать при запуске все, достаточно загрузить только то, что пользователь ожидает увидеть при загрузке приложения. Однако не рекомендуется отложено загружать маршрут по умолчанию. Предположим, мы имеем следующую конфигурацию:
1 2 3 4 |
const routes: Routes = [ { path: '', redirectTo: '/mymodule', pathMatch: 'full' }, { path: 'mymodule', loadChildren: './mymodule.module#MyModule' } ]; |
Когда пользователь открывает приложение, он будет перенаправлен к маршруту /mymodule, который вызовет отложенную загрузку MyModule. Это приведет к дополнительному HTTP-запросу для загрузки mymodule.module и некоторым ненужным операциям (парсинг и оценка JavaScript VM). В результате это замедляет первоначальный рендеринг страниц. Поэтому рекомендуется объявить маршрут по умолчанию как неотложенный.
8. Перехватывайте все ошибки с помощью специального обработчика ошибок
Angular предоставляет встроенную глобальную службу обработки исключений, поэтому при возникновении ошибки эта служба перехватывает ее и выводит данные об ошибке в консоль. Мы можем расширить этот обработчик исключений, чтобы добавить некоторые дополнительные функции, такие как отправка ошибки на ваш back-end сервер для анализа или другой обработки.
Расширение обработчика ошибок Angular
Расширение обработчика ошибок Angular выполняется довольно просто. Все, что нам нужно сделать, это создать класс, который расширяет ErrorHandler Angular и переопределяет метод handleError. Пример:
1 2 3 4 5 6 7 8 9 10 11 12 |
import {ErrorHandler} from '@angular/core'; export class AppErrorHandler extends ErrorHandler { constructor(){ super(false); } public handleError(error: any): void { // Добавьте здесь свою логику. super.handleError(error); } } |
После этого нам нужно зарегистрировать пользовательский AppErrorHandler в app.module.ts:
1 2 3 4 5 6 7 8 |
@NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule ], bootstrap: [ AppComponent ], providers: [ {provide: ErrorHandler, useClass: AppErrorHandler} ] }) |
Оберните аргументы console.log в литерал объекта, чтобы вывести имя переменной вместе со значением.
1 2 |
console.log(isLoggedIn) console.log({ isLoggedIn }) |
Спасибо за внимание, я надеюсь, что эта статья вам понравилась! Если у вас есть другие советы и рекомендации, напишите об этом в комментариях.
Автор: Alexandru Bereghici
Источник: //medium.com/
Редакция: Команда webformyself.