Обнаружение изменений в структуре Angular является однонаправленным и нисходящим (в отличие от циклов дайджеста в AngularJS). Каждый раз, когда запускается асинхронное событие, такое как событие DOM, обратный вызов таймера, обработчик XHR, код приложения обычно обновляет состояние (или модель) в этих обратных вызовах. Angular с помощью zone.js обнаруживает эти асинхронные события и автоматически запускает обнаружение изменений (*). Он проверяет наличие изменений состояния, проходящих по дереву пользовательского интерфейса, начиная с корневого компонента, и выполняет необходимые обновления DOM, чтобы отразить обновленное состояние. Состояние может иметь любую структуру данных (массивы, множества, карты, объекты, примитивы), которая связана как привязки свойств в шаблонах компонентов.

Angular поддерживает два типа стратегий обнаружения изменений:

  • Дефолт
  • OnPush

Обнаружение изменений по умолчанию

В режиме обнаружения изменений по умолчанию Angular проверяет наличие изменений для каждого компонента пользовательского интерфейса. Эти проверки выполняются намного быстрее, чем проверки цикла дайджеста в AngularJS, из-за способа, которым Angular генерирует эти дружественные к виртуальным машинам классы детекторов изменений (когда код предварительно скомпилирован с помощью компиляции Ahead of Time (AOT)).

Пример:

Вот сетка, состоящая из нескольких ячеек (все угловые компоненты). Щелчок по любой ячейке изменяет состояние приложения, относящееся (только) к этой ячейке. Желтая рамка появляется вокруг ячейки всякий раз, когда Angular запускает в ней обнаружение изменений.



Клики в действии (gif):

Как вы можете видеть на гифке ниже, щелчок по любой ячейке приводит к тому, что Angular запускает обнаружение изменений во всех ячейках.

Хотя обнаружение изменений по умолчанию выполняет свою работу без какой-либо дополнительной сложности кода, оно станет узким местом производительности в сложных одностраничных приложениях, когда через систему проходит множество событий.

Обнаружение изменений OnPush

Со стратегией обнаружения изменений OnPush Angular будет пропускать обнаружение изменений для компонента, пока ссылки на входы не изменяются (неизменяемые). Чтобы обновить состояние, вместо изменения объектов код приложения должен возвращать новые ссылки. Эту опцию можно эффективно использовать, чтобы Angular пропускал логику обнаружения изменений для больших поддеревьев пользовательского интерфейса, делая их входные данные неизменяемыми.

Этот подход эквивалентен использованию ловушки жизненного цикла shouldComponentUpdate () в React для сокращения ненужных циклов рендеринга.

Пример:

Вот модифицированная версия приведенного выше примера с обнаружением изменений OnPush.



// Instead of mutating the flip status of the clicked cell,
// a new object is created with the updated status and replaces the // original cell in the list.
let updatedCell = Object.assign({}, this.currentState.cells[index], {
    flip: !this.currentState.cells[index].flip
});
    
this.currentState.cells = [
   ...this.currentState.cells.slice(0, index),
   updatedCell,
   ...this.currentState.cells.slice(index + 1)
];

Клики в действии (gif):
Как вы можете видеть на гифке ниже, щелчок по ячейке заставляет Angular запускать обнаружение изменений ТОЛЬКО для этой конкретной ячейки. Для всех остальных ячеек проверки обнаружения изменений были полностью пропущены.

Такой подход, очевидно, делает цикл обнаружения изменений намного более производительным, однако введение неизменяемых объектов состояния принесет свои сложности и проблемы.

Ссылки:

Благодарим @ dryzhk0v за рассмотрение проекта и отзыв.