Распространенные ошибки¶
Создание Angular приложения просто невозможно без ошибок. Но не всегда очевидно, в каком месте или даже в какой части кода она таится, а ее поиск порой может отнять немало времени.
Для предупреждения таких ситуаций ниже приведен перечень с подробным описание наиболее часто допускаемых разработчиками ошибок, знание о которых может значительно облегчить вам жизнь и сэкономить время.
Использование private переменных в шаблоне¶
Все свойства компонента или сервиса, которые объявлены с модификатором private
, должны использовать исключительно в пределах своего класса. Обращение к ним в шаблоне или другом сервисе или компоненте (в случае с сервисом) приведет к генерации исключения, но только в момент сборки приложения.
Воспроизведение ошибки.
1 2 3 4 5 6 7 8 9 |
|
Далее выполняем сборку.
1 |
|
В результате в консоли должен быть следующий текст ошибки:
1 |
|
Обращение сервисов друг к другу¶
При проектировании архитектуры приложения важно однонаправленное использование сервисов.
Например, имеется два сервиса: ServiceA
и ServiceB
. И если ServiceA
использует ServiceB
, то ServiceB
уже не может обращаться к ServiceA
.
Воспроизведение ошибки.
example1.service.ts
1 2 3 4 |
|
example2.service.ts
1 2 3 4 |
|
После того как изменения вступят в силу в консоли будет выведено предупреждение:
1 2 3 4 5 6 7 |
|
И хотя это только предупреждение и оно не ограничивает работу приложения, это считается грубой ошибкой проектирования.
Объект в качестве значения @Input() свойства¶
Нередко в качестве значения компоненту через свойство @Input()
передается объект, при этом в принимающем компоненте в ngOnChanges()
определяется функция-обработчик, которая должна выполняться при любом изменении в объекте.
Но если изменить значение какого-либо свойства или же добавить новое свойство, то компонент не увидит изменений, поскольку в JavaScript передача объекта осуществляется по ссылке.
Воспроизведение ошибки.
my-orders.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
order-item.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Получается, что для вызова функции в ngOnChanges()
нужно вернуть новый объект. Это можно сделать, например, так:
1 2 3 4 |
|
Дублирование подписчиков в RxJS¶
При определении создании нового подписчика для объекта Observable
может случиться, что функция подписчика для обработки получаемого значения будет вызываться несколько раз.
Такое происходит, когда при разрушении компонента подписчик не отписывается от незавершенного Observable
. То есть функция будет выполняться даже несмотря на то, что компонент уже не существует. Например, к этой категории относятся определения обработчиков событий смены маршрута.
Но самое интересное, что при следующем переходе на этот же компонент будет создан еще один подписчик. И когда от объекта Observable
придет значение, функция-обработчик будет вызвана столько раз, сколько к этому моменту будет подписчиков.
Воспроизведение ошибки.
1 2 3 4 5 6 |
|
Часто бывает очень трудно выявить подобную ошибку, поэтому для избежания такой ситуации всегда вызывайте в ngOnDestroy()
метод unsubscribe()
у всех объектов Subscription
.
1 2 3 |
|
ExpressionChangedAfterItHasBeenCheckedError¶
Ошибка Expression Changed After It Has Been Checked одна из самых распространенных и непонятных в Angular и не всегда ее можно распознать сразу.
В консоли браузера она выглядит следующим образом:
или
Чтобы исправить такую ошибку, или лучше вовсе избежать ее, нужно понимать причину ее возникновения.
При каждом запуске цикла проверки изменений при первой его итерации Angular запоминает значения всех свойств всех компонентов, которые использовались для выполнения текущей операции. Эти значения хранятся в свойстве oldValues
объекта представления (шаблона) в каждом компоненте.
Во время второй итерации идет сравнение текущих значений с теми, которые были запомнены на прошлом шаге. А именно Angular проверяет равны ли значения свойств, переданных дочернему компоненту, значениям свойств текущего компонента. Также сравниваются свойства, используемые для отображения в шаблоне. Вторая итерация повторяется для каждого дочернего компонента.
Интересно, что сравнение значений свойств выполняется только в режиме development
.
ExpressionChangedAfterItHasBeenCheckedError
возникает, когда в процессе проверки Angular видит, что хотя бы одно из запомненных ранее значений изменилось.
Воспроизведение ошибки.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Поскольку верификация значений затрагивает представление, следовательно, все изменения, сделанные до вызова ngAfterViewInit()
, не инициируют возникновение ошибки.
Сама проверка необходима, чтобы убедиться в стабильности иерархической структуры. Все изменения родительского компонента, затрагивающие дочерние компоненты, должны быть синхронизированы и зафиксированы.
Но если вам действительно необходимо выполнить действие именно в момент верификации, то ситуация может быть разрешена либо с помощью отложенного выполнения, например, с помощью функции setTimeout()
, либо принудительным запуском нового цикла проверки изменений (ChangeDetection
)
1 2 3 |
|