setTimeout(() => { ... })
, вероятно, является наиболее популярным хаком для решения некоторых распространенных проблем рендеринга в Angular, таких как печально известная ошибка Expression has changed after it was checked
, и во многих других сценариях, когда представление не обновляется. Тем не менее частое использование этого хака может также указывать на недостаточное понимание жизненного цикла и механизма обнаружения изменений в Angular. Возникновение проблемы рендеринга обычно означает, что что-то идет не так в текущем цикле обнаружения изменений. Проблема использования setTimeout(() => { ... })
заключается в том, что он не устраняет основную причину. Он разделяет фрагменты кода на новый цикл обнаружения изменений, в то время как основная причина все еще остается нерешенной. Это все равно что перезапустить сломанную программу, не разобравшись в причинах возникновения в ней ошибок. Будущие изменения кода могут с легкостью сломать ее снова. Более того, этот подход также вызывает проблемы с производительностью.
Можно с уверенностью сказать, что в 90% случаев использования setTimeout(() => { ... })
для решения проблемы, существуют лучшие альтернативы без setTimeout()
.
Другим распространенным признаком неправильного понимания является постоянное использование аннотации ViewChild для связи между компонентами, например для вызова метода публичного компонента, чтения атрибутов компонентов и т.д. Проблема здесь не в функциональности, а в удобстве обслуживания. При использовании ViewChild для получения доступа управлять циклом изменений компонентов приходится вручную. В этом случае не стоит полагаться на жизненный цикл Angular для управления состояниями, поскольку в результате получается много избыточного кода. Его будет намного легче поддерживать, если заменить как можно больше публичных вызовов и чтений на привязки атрибутов и событий.
Один из интересных феноменов в Angular состоит в том, что многие преобразуют все используемые подписки в промисы. Причина вполне понятна: концепция подписки в Angular взята из библиотеки RxJS и не столь известна по сравнению со встроенным промисом. Тем не менее, чтобы стать мастером Angular, не стоит игнорировать RxJS. Причина в том, что Angular использует библиотеку RxJS в качестве одной из основ. Подписку можно найти в Angular повсюду, например в HTTP-вызовах, маршрутах, событиях и т.д. Преобразование всех подписок приводит к неоправданным накладным расходам с точки зрения как производительности, так и удобства обслуживания. Кроме того, поскольку подписка предоставляет более надежные функциональные возможности, чем промисы, на ее основе существует множество шаблонов проектирования. Они встречаются довольно часто в некоторых крупных проектах. Кроме того, существует много библиотек Angular на основе RxJS, таких как NgRx Store.
Последняя ошибка не столь понятна и очевидна, как остальные три выше. В Angular существует два распространенных способа вызова функций в шаблоне. Первый — вызов через прямой вызов функции:
@Component({
template: `<div>{{ getUserName() }}</div>`
})
export clas TestComponent {
...
getUserName(): string {
return 'username';
}
}
Второй — вызов через метод getter:
@Component({
template: `<div>{{ userName }}</div>`
})
export clas TestComponent {
...
get userName(): string {
return 'username';
}
}
Тот, кто хорошо разбирается в механизме обнаружения изменений, будет изо всех сил стараться избегать этого при использовании стратегии по умолчанию. Причина в том, что вызов функции в шаблоне портит механизм обнаружения изменений в Angular, поскольку он не может отслеживать функции, в отличие от простых атрибутов. В результате все вызовы функций в шаблонах всегда будут перезапускаться в каждом цикле обнаружения изменений. При наличии функциональности, которая часто запускает обнаружение изменений, например привязки к событиям mousemove
, повторное выполнение функций станет причиной снижения производительности. Следовательно, вызов функции в шаблоне — это то, чего мастер Angular должен по возможности избегать.
Перевод статьи Andrew Sproul: The Old Saying: “Two Heads are Better than One.”
Комментарии