Шляхом брудної перевірки $scopeоб’єкта
Кутовий підтримує простоту arrayспостерігачів у $scopeоб’єктах. Якщо ви оглянете будь-яке $scope, то виявите, що він містить arrayдзвінок $$watchers.
Кожен спостерігач - це objectте, що міститься серед іншого
- Вираз, за яким спостерігає спостерігач. Це може бути просто
attributeім'я або щось складніше.
- Останнє відоме значення виразу. Це можна перевірити відповідно до поточного обчисленого значення виразу. Якщо значення різняться, спостерігач запустить функцію та позначить
$scopeяк брудне.
- Функція, яка буде виконуватися, якщо спостерігач забруднений.
Як визначаються спостерігачі
У AngularJS існує багато різних способів визначення спостерігача.
Ви можете явно на .$watchattribute$scope
$scope.$watch('person.username', validateUnique);
Ви можете розмістити {{}}інтерполяцію у своєму шаблоні (спостерігач буде створений для вас на поточний $scope).
<p>username: {{person.username}}</p>
Ви можете попросити таку директиву, як ng-modelвизначити спостерігача для вас.
<input ng-model="person.username" />
$digestЦикл перевіряє всі спостерігач проти останнього значення
Коли ми взаємодіємо з AngularJS через звичайні канали (ng-модель, ng-повторення тощо), директива спричинить цикл дайджесту.
Дайджест циклу - це перше глибинне подолання $scopeвсіх його дітей . Для кожного $scope objectми повторюємо його $$watchers arrayта оцінюємо всі вирази. Якщо нове значення виразу відрізняється від останнього відомого значення, викликається функція спостерігача. Ця функція може перекомпілювати частину DOM, перерахувати значення $scope, запустити an AJAX request, все, що вам потрібно для цього.
Кожна область обходить і кожен вираз перегляду оцінюється та перевіряється на останнє значення.
Якщо спостерігач спрацьовує, то $scopeбрудний
Якщо спрацьовує спостерігач, програма знає, що щось змінилося, і $scopeпозначка є брудною.
Функції Watcher можуть змінювати інші атрибути на $scopeбатьківщині або на ній $scope. Якщо одна з $watcherфункцій була запущена, ми не можемо гарантувати, що інші $scopeз них ще чисті, і тому ми виконуємо весь цикл дайджесту знову.
Це пояснюється тим, що AngularJS має двосторонню прив'язку, тому дані можуть передаватися назад в $scopeдерево. Ми можемо змінити значення на вище $scope, яке вже було засвоєно. Можливо, ми змінимо значення на $rootScope.
Якщо $digestбрудний, ми виконуємо весь $digestцикл знову
Ми постійно перебираємо $digestцикл, поки цикл дайджесту не з’явиться чистим (усі $watchвирази мають те саме значення, що і в попередньому циклі), або не досягнемо межі дайджесту. За замовчуванням ця межа встановлена на рівні 10.
Якщо ми досягнемо границі дайджесту, AngularJS призведе до помилки в консолі:
10 $digest() iterations reached. Aborting!
Дайджест важкий для машини, але простий для розробника
Як бачите, щоразу, коли щось змінюється у програмі AngularJS, AngularJS перевірятиме кожного спостерігача в $scopeієрархії, щоб побачити, як реагувати. Для розробника це велика прибутковість продуктивності, тому що зараз вам потрібно майже не писати код електропроводки, AngularJS просто помітить, чи змінилося значення, і зробить решту додатку узгодженою зі зміною.
З точки зору машини, але це дико неефективно і сповільнить наш додаток, якщо ми створимо занадто багато спостерігачів. Місько процитував цифру близько 4000 спостерігачів, перш ніж ваш додаток буде відчувати себе повільно у старих браузерах.
Цю межу легко досягти, наприклад, якщо ви ng-repeatперевищуєте велику JSON array. Ви можете пом'якшити це, використовуючи такі функції, як одноразове прив'язування для складання шаблону без створення спостерігачів.
Як уникнути створення занадто багато спостерігачів
Щоразу, коли ваш користувач взаємодіє з вашим додатком, кожен відвідувач вашої програми буде оцінюватися хоча б один раз. Значна частина оптимізації програми AngularJS - це зменшення кількості спостерігачів у вашому $scopeдереві. Один з простих способів зробити це - одноразове зв’язування .
Якщо у вас є дані, які рідко змінюватимуться, ви можете зв'язати їх лише один раз за допомогою синтаксису ::, наприклад:
<p>{{::person.username}}</p>
або
<p ng-bind="::person.username"></p>
Прив’язка буде ініційована лише тоді, коли буде наданий шаблон, що містить, і дані завантажені в нього $scope.
Це особливо важливо, коли у вас є ng-repeatбагато предметів.
<div ng-repeat="person in people track by username">
{{::person.username}}
</div>