Как обрабатываются наблюдатели и фильтры в цикле дайджеста AngularJS?

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

  • Они выполняются одинаковое количество циклов?

  • Оба вызваны одними и теми же обстоятельствами?


person luisfarzati    schedule 16.10.2013    source источник


Ответы (1)


Часы проверяются каждый цикл дайджеста. И $watch может просматривать выражение Angular. Внутри выражения может быть фильтр, который Angular должен оценивать (используя $interpolate), чтобы определить, изменилось ли отслеживаемое выражение.

Оба события вызваны одними и теми же обстоятельствами?

Таким образом, фильтры не запускаются непосредственно $digest, а запускаются как следствие $watch. По сути, фильтры запускаются оценкой отслеживаемых выражений.

Есть несколько причин, по которым о фильтрах говорят особенно в отношении производительности $digest. Глядя на эти два выражения:

Выражение 1: {{searchText+2}}

Выражение 2: {{searchText | myFilter:true}}

Оба выражения будут оцениваться каждый раз, когда срабатывает $digest. Таким образом, одна из областей риска заключается в том, что myFilter может быть сложным и в конечном итоге использовать гораздо больше циклов процессора, чем что-то простое (например, +2 выше).

Немного менее очевидно, что фильтр может вызвать дополнительные запуски всех наблюдателей, если он не идемпотентный. При каждом запуске $digest устанавливается грязный бит, если какие-либо часы приводят к изменению. И он снова запускает все часы, если этот грязный бит установлен. Это позволяет распространять любые изменения. Например, если searchText изменяется одним из наблюдателей, то Angular должен дать всем остальным наблюдателям возможность увидеть, зависят ли их результаты от searchText и, следовательно, должны измениться.

В этом заключается разница между выражениями 1 и 2 выше. В худшем случае представьте, что myFilter возвращает случайное число. $digest запускается, видит изменение при оценке часов (предыдущий результат фильтра не соответствует новому результату), поэтому снова проходит по списку наблюдения. Поскольку фильтр возвращает случайное число, его результаты, скорее всего, изменились, вызывая еще один запуск $digest. и т. д. и т. д. Angular имеет встроенную остановку после 10 циклов по своему списку наблюдения — он считает, что если результаты не стабилизируются после 10 попыток, значит, что-то не так, и поэтому он отказывается от выбрасывания «Ошибка: 10 $ digest () достигнуто итераций. Прерывание!"

Они выполняются одинаковое количество раз?

Поэтому каждое отслеживаемое выражение (включая любые фильтры) запускается как минимум дважды за $digest. Один раз из-за изменения, вызвавшего $digest, и еще раз, чтобы проверить, нужно ли распространять этот результат. Если это распространение привело к каким-либо изменениям, часы и фильтры будут запускаться снова, пока ничего не изменится.

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

person KayakDave    schedule 15.01.2014
comment
Потрясающее объяснение, спасибо. Извините, я получил ваш ответ вскоре после моего вопроса, но потом я просто забыл его принять! - person luisfarzati; 13.04.2014