Яка різниця між $ evalAsync та $ timeout у AngularJS?


180

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

Нещодавно я намагався краще і глибше зрозуміти дайджест циклу, і мені траплялося функцію $ evalAsync .

Схоже, що ця функція дає подібні результати $timeout, тільки ви не даєте їй затримки. Кожен раз, коли я його використовував $timeout, був із затримкою 0, тому тепер мені цікаво, чи варто було б я використовувати це $evalAsyncзамість цього.

Чи є якісь принципові відмінності між ними? Які випадки ви використовуєте один над іншим? Я хотів би краще зрозуміти, коли використовувати який.

Відповіді:


263

Нещодавно я відповів по суті на це запитання тут: https://stackoverflow.com/a/17239084/215945 (Ця відповідь посилається на деякі біржі github з Міськом.)

Узагальнити:

  • якщо в черзі код використовується $ evalAsync з директиви , він повинен запускатися після того, як DOM маніпулює Angular, але до того, як браузер відображатиме
  • якщо код ставиться в чергу, використовуючи $ evalAsync від контролера , він повинен запускатися до того, як DOM маніпулює Angular (і до того, як браузер відображатиметься) - рідко вам цього потрібно?
  • якщо код вставлений у чергу з використанням $ timeout , він повинен запускатися після того, як DOM маніпулює Angular, і після надання браузера (що може спричинити мерехтіння в деяких випадках)

15
Дякую за пояснення. Я не впевнений, що розумію. Чому це має значення, якщо ви телефонуєте $ evalAsync з контролера чи директиви? AsyncQueue не знає, чи був він зареєстрований у контролері чи директиві, він просто висуває черги в поточну область. Це має відношення до того, коли матеріал працює в контролері та контролері? Я просто хочу зрозуміти цю частину.
dnc253

@ dnc253, я не переглянув кутовий код, тому не знаю відповіді на ваше (добре) запитання. Сподіваємось, хтось ще може прокоментувати.
Марк Райкок

15
чи означає "з директиви" означає "від функції зв'язування директиви"? Або це правда щодо поведінки, яка виконується або методом посилання, або контролером директиви?
SimplGy

5
так, насправді незрозуміло, що тут означає "під
керівництвом

1
@MarkRajcok, чи можете ви уточнити тут: якщо код ставиться в чергу, використовуючи $ evalAsync з директиви, він повинен запускатися після того, як DOM був маніпульований Angular - чи повинен він працювати після того, як DOM був маніпульований цією директивою чи іншими директивами?
Макс Корецький

59

Для тих, хто будує складні програми, пам’ятайте, що на ваш вибір впливає ефективність роботи. Також я хотів би доповнити Марк відповідь більш детальними технічними деталями:

  • $ timeout (зворотний виклик) чекатиме завершення поточного циклу дайджесту (тобто, кутове оновлення всієї моделі та DOM), тоді він виконає зворотний виклик - потенційно впливає на кутову модель - потім запустить повний $applyкорінь в області root $ і перенаправить все.

  • $ evalAsync (зворотний виклик) , з іншого боку, додасть зворотний виклик до поточного або наступного циклу дайджесту. Що означає, що якщо ви знаходитесь у циклі дайджесту (наприклад, у функції, яка викликається з якоїсь ng-clickдирективи), це нічого не чекатиме, код буде виконуватися відразу. Якщо ви знаходитесь в асинхронному дзвінку, наприклад, a setTimeout, $applyбуде запущений новий цикл дайвінгу ( ).

Тож щодо продуктивності завжди краще зателефонувати $evalAsync, якщо тільки для вас не важливо, щоб перегляд був оновлений перед виконанням вашого коду, наприклад, якщо вам потрібен доступ до якогось атрибута DOm, такого як ширина елементів тощо.

Якщо ви хочете отримати детальнішу інформацію про відмінність між $ timeout, $ evalAsync, $ digest, $ apply, я запрошую вас прочитати мою відповідь на це інше питання: https://stackoverflow.com/a/23102223/1501926

Також обов’язково прочитайте документацію :

$ EvalAsync не дає гарантій щодо того, коли буде виконуватися вираз, лише це:

  • він буде виконуватися після функції, яка запланувала оцінку (бажано до надання DOM).
  • принаймні один цикл дайджестів $ буде виконано після виконання виразу.

Примітка: якщо ця функція викликається поза циклом перетворення $, буде заплановано новий цикл перебору $ . Однак рекомендується завжди код виклику, який змінює модель зсередини виклику $ застосовувати. Це включає код, оцінений за допомогою $ evalAsync.


Чи можете ви поясніть, чому потрібен $ timeout, якщо мені потрібно отримати доступ до деякого атрибута DOM. Скажімо, якщо я <table width = "{{x}}"> Чи не функція годинника ng-bind не оновлює атрибут dom у пам'яті, я розумію, що у нього не буде шансів перефарбувати подання, поки не закінчиться цикл дайджесту.
Шрідхар Чидурала

2
@SridharChidurala, оскільки DOM ("HTML") оновлюється під час циклу дайджесту, вам доведеться почекати, коли це буде зроблено, перш ніж ви зможете прочитати мотивації. Однак це не перешкоджає Angular, вам слід читати xбезпосередньо зі своєї області, а не з DOM, тому вам нічого не потрібно чекати. Крім того, вам слід краще використовувати ng-stylecss, а не застаріле widthвластивість. Якщо вам потрібна додаткова допомога, відкрийте нове запитання на StackOverflow.
floribon
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.