Apply і $ digest в angularjs

Два основних аспекти в AngularJS, які можуть ввести в оману це $ apply і $ digest. Мета статті постаратися пояснити, що це за функції і чим вони можуть бути корисні при щоденному програмуванні на AngularJS.

Досліджуємо $ apply і $ digest

Як відомо, AngularJS має неймовірну можливістю в особі двостороннього зв'язування даних та подання, яке багато разів полегшує нашу з вами життя. Це означає, що коли ви щось міняєте на сторінці, то і модель даних в scope оновлюється автомагіческі. Відповідно, коли спершу модель даних в scope зміниться, то і уявлення на сторінці зміниться. Як AngularJS це робить?

Коли ви пишете вираз (>), то AngularJS непомітно навішує функцію відстеження (watcher), яка оновлює уявлення при зміні моделі. Функція відстеження точно така ж як ви самі можете написати в scope.

Другим аргументом передається функція слухач (listener), яка викликається кожен раз, коли значення aModel змінюється.
Легко зрозуміти, що коли значення моделі змінюється, то спрацьовує слухач, оновлюючи вираз в HTML. Але є ще головне питання! Як AngularJS розуміє, що необхідно викликати функцію слухача? Іншими словами як AngularJS дізнається, що модель змінилася, щоб потім викликати функцію слухача? Може він запускає цю функцію з якою періодичністю для перевірки зміни значення моделі в scope. Ось тут вступає в роботу цикл $ digest.
Під час даного циклу запускаються функції відстеження. Після цього AngularJS розраховує значення моделі і якщо воно змінилося, то відповідна функція слухача запускається. Наступне питання - де і коли запускається цикл $ digest?
Він запускається після виклику $ scope. $ Digest (). Припустимо, що ви міняєте модель scope через функцію обробки натискання директиви
ng-click. В цьому випадку AngularJS автоматично запускає цикл $ digest. І вже після запуску спрацьовує кожен з функцій відстеження. Ці функції перевіряють поточне значення моделі в порівнянні з розрахованим значенням. Якщо вони розрізняються, то відповідна функція слухача виконується. В результаті всі вирази на сторінці оновляться. На додаток до ng-click є ще кілька директив / сервісів, які дозволяють змінювати модель і автоматично запускати $ digest цикл. (Ng-model. $ Timeout).
Поки все начебто зрозуміло, але є маленький нюанс. AngularJS не викликає $ digest безпосередньо, замість цього він використовує $ scope. $ Apply (). який в свою чергу викликає $ rootScope. $ digest (). В результаті він послідовно обходить всі дочірні scope і викликає функції відстеження у кожного.
Уявімо, що ви навісили директиву ng-click на кнопку і прописали функцію для неї. Коли натиснете на кнопку, AngularJS оберне функцію в $ scope. $ Apply (). Тобто ваша функція виконається, як зазвичай, оновить модель (якщо треба) і далі вже запускається $ digest цикл, щоб зміни відобразилися на сторінці.
Примітка. $ Scope. $ Apply () автоматично запускає $ rootScope. $ Digest (). Функція $ apply () йде з двома конструкторами. Перший - приймає функцію як аргумент, виконує її, а потім запускає $ digest цикл. Другий - не приймає аргументи і просто запускає $ digest цикл. Далі ми побачимо чому варіант з аргументом краще.

Там, де необхідно викликати $ apply () в коді?

Якщо AngularJS обертає наш код в $ apply () і починає цикл $ digest. то в яких випадках нам необхідно викликати $ apply в коді? AngularJS дуже простий в даному моменті. Модель змінюється тільки всередині контексту AngularJS. Тобто код, який змінює модель всередині, обгорнутий $ apply (). Вбудовані директиви AngularJS вже це роблять, тому будь-які зміни в моделі відображаються на сторінці. Як би там не було, якщо ви зміните модель поза контекстом AngularJS, то вам буде потрібно проінформувати AngularJS про ці зміни шляхом виклику функції $ apply () в коді, а він вже запустить функції відстеження і ваші зміни коректно вступлять в силу.

Наприклад, якщо ви використовуєте функцію JS setTimeout () для поновлення моделей scope. AngularJS жодним чином про цю зміну не впізнає. В цьому випадку відповідальність за оповіщення AngularJS на ваших плечах і ви повинні в коді викликати $ apply (). який вже запустить $ digest цикл.

Так само якщо у вас є своя директива, яка навішує на DOM різні слухачі подій і змінює деякі моделі всередині обробника, то вам необхідно викликати $ apply () для того, щоб бути впевненими, що зміни вступлять в силу.

Давайте поглянемо на приклад. Мається на увазі, що у вас є сторінка і ви хочете відобразити на ній повідомлення з затримкою в 2 секунди. Реалізація буде приблизно наступна:

Запустивши оновлений приклад, ви побачите оновлення сторінки через 2 секунди. Єдина зміна в коді в порівнянні з попереднім прикладом то, що ми обернули код в $ scope. $ Apply (). який автоматично запустив $ rootScope. $ digest (). В результаті всі функції відстеження запустилися і значення моделі на сторінці оновилося.

Примітка. Намагайтеся завжди використовувати сервіс $ timeout. коли це можливо, який є тим же самим setTimeout (). який автоматично обертається в $ apply і вам не доведеться його дописувати в коді.

Так само зауважте, що в прикладі коду наведеному нижче, модель оновлюється як зазвичай, але в кінці використовується $ apply () без аргументів.

Дана версія методу використовує $ scope. $ Apply () без аргументів, але код і раніше працює. Але пам'ятайте, що ви завжди повинні використовувати $ apply () з аргументами. Це тому, що передана функція як аргумент обертається ще блоком try. catch і якщо виникне виключення, то воно пройде через сервіс $ exceptionHandler

Скільки разів запускається цикл $ digest?

Коли цикл дайджест запускається, то функції відстеження виконуються для перевірки зміни моделі в scope. Якщо вона змінилася, то відповідні функції слухачів запускаються. Це веде до важливого питання. А що якщо слухач теж змінює модель? Як AngularJs відреагує на це?
Відповідь наступна: цикл $ digest одним запуском не обмежений. В кінці поточного циклу, він заново запускається, щоб перевірити зміна моделі. В принципі це «брудна перевірка» (dirty checking) і вона робиться для відстеження змін, які могли статися в слухачах. Тому цикл запускається з разу в раз, поки не закінчиться зміна моделі або він не досягне максимального числа ітерацій - 10. Так, що завжди добре залишатися ідемпотентна і спробувати мінімізувати зміна моделі всередині функції слухачів.

Примітка. Цикл $ digest запускається мінімум 2 рази, якщо немає зміни моделей у функціях слухачів. Як описано вище, він запускається знову і знову, щоб упевнитися, що значення моделі стабільно і в ній немає зміни.

висновок:

Поділитися посиланням: