Как узнать, когда начинается цикл (или завершение) цикла дайджест 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.

В комментариях к моему первоначальному вопросу возникла некоторая путаница в том, почему вы хотели бы сделать такие вещи: если вы все еще неясны, посмотрите этот пост в блоге я написал, который охватывает мой конкретный случай использования.