Как узнать, когда начинается цикл (или завершение) цикла дайджест Angular.js?
У меня есть приложение Angular.js, которое выполняет большой набор расчетов типа учета (доход, затраты, прибыль и т.д.) по сложной объектной модели. Для изменения любой части объектной модели необходимо выполнить все вычисления. Кроме того, многие изменения в объектной модели могут быть сделаны непосредственно из моих шаблонов с использованием привязок - нет необходимости в промежуточном контроллере.
Многие из результатов расчета должны отображаться пользователю и вносить вклад в последующие вычисления. Например, доход отображается пользователю, но также используется для расчета прибыли (которая также отображается пользователю). Тем не менее, нет смысла вычислять доход в два раза (это сложный расчет) в каждом цикле дайджеста, поэтому очевидная оптимизация заключается в том, чтобы memoize, когда он сначала вычисляется, а затем повторно использует это memoized значение для продолжительности цикла.
Проблема в том, что мне нужно очистить эти мемуары либо в начале, либо в конце цикла дайджеста. Один из подходов состоял бы в том, чтобы контроллер мог перехватывать все возможные источники изменений и вручную обезличивать объектную модель, прежде чем приступать к вычислениям. Вместо этого я бы предпочел просто использовать привязки, которые были настроены.
Насколько я могу судить, мне нужен способ узнать, начинается ли цикл дайджест или когда он закончен. Когда я получаю это уведомление, я мог бы reset записать мемуары.
В документации Angular $ говорится:
Если вы хотите получать уведомления при вызове $digest, вы можете зарегистрируйте функцию watchExpression без прослушивателя. (Поскольку watchExpression может выполняться несколько раз за цикл $digest, когда изменение будет обнаружено, подготовиться к нескольким вызовам вашего слушателя.)
Это бесполезно для меня, потому что очистка мемуазов на каждой итерации цикла дайджеста приведет к поражению цели их использования в первую очередь. Мне нужно только одно уведомление за цикл дайджест.
Как я могу это сделать или есть альтернативный подход к решению проблемы?
Ответы
Ответ 1
ОК, я думаю, что, наконец, я понял что-то, поэтому подумал, что я отвечу на свой вопрос.
Существует частный Angular метод под названием $$postDigest
, который будет отсылать функцию после окончания следующего цикла дайджеста. Однако он работает только один раз, и если вы попытаетесь заставить его перенести себя рекурсивно, он перейдет в бесконечный цикл.
Чтобы обойти это, вы можете вместо этого использовать $$postDigest
в сочетании с регулярным $watch
. Если у вас есть функция с именем fn
, которую вы хотите, чтобы контроллер вызывал после каждого цикла дайджест, вы добавили бы что-то вроде этого в функцию контроллера:
...
var hasRegistered = false;
$scope.$watch(function() {
if (hasRegistered) return;
hasRegistered = true
// Note that we're using a private Angular method here (for now)
$scope.$$postDigest(function() {
hasRegistered = false;
fn();
});
});
...
Это основано на фрагменте кода Karl Seamon. Очевидно, что это не идеальный вызов частного метода на $scope
. Надеемся, что метод $postDigestWatch
вдоль этих строк может быть добавлен в Angular.
В комментариях к моему первоначальному вопросу возникла некоторая путаница в том, почему вы хотели бы сделать такие вещи: если вы все еще неясны, посмотрите этот пост в блоге я написал, который охватывает мой конкретный случай использования.