Подтвердить что ты не робот

Как остановить цикл дайджеста вручную в angularjs

Как цикл дайджест выполняет грязную проверку переменной, которая есть, если имеется 100 переменных области видимости, и если я изменяю одну переменную, тогда она будет запускать просмотр всех переменных.

Предположим, что у меня есть 100 переменных модели области видимости, которые не зависят друг от друга. Если я вношу изменения в одну переменную, то я не хочу проверять все остальные 99 переменных. Есть какой-либо способ сделать это? Если да, то как?

4b9b3361

Ответ 1

Удивительно, но это обычно не проблема, у браузеров нет проблем даже с тысячами привязок, если выражения не сложны. Общий ответ для how many watchers are ok to have: 2000.

Решения:

Это довольно легко от AngularJS 1.3, так как привязки one-time теперь находятся в ядре.

  • Один раз привязка переменных.

Мы можем использовать директиву (::), привязавшуюся к одному времени, чтобы предотвратить наблюдение за нежелательными переменными. Здесь переменная будет смотреть только один раз и после этого не будет обновлять эту переменную.

  1. Остановить цикл дайджеста вручную.

HTML:

<ul ng-controller="myCtrl">
  <li ng-repeat="item in Lists">{{lots of bindings}}</li>
</ul>

Код контроллера:

app.controller('myCtrl', function ($scope, $element) {
  $element.on('scroll', function () {
    $scope.Lists = getVisibleElements();
    $scope.$digest();
  });
});

Во время $digest вас интересуют изменения в объекте Lists, а не изменения отдельных элементов. Тем не менее, Angular будет допрашивать каждого наблюдателя за изменениями.

для stop и pause дайджест:

app.directive('stopDigest', function () {
  return {
    link: function (scope) {
      var watchers;

      scope.$on('stop', function () {
        watchers = scope.$$watchers;
        scope.$$watchers = [];
      });

      scope.$on('resume', function () {
        if (watchers)
          scope.$$watchers = watchers;
      });
    }
  };
});

Теперь, код контроллера должен быть изменен:

<ul ng-controller="listCtrl">
  <li stop-digest ng-repeat="item in visibleList">{{lots of bindings}}</li>
</ul>

app.controller('myCtrl', function ($scope, $element) {
  $element.on('scroll', function () {
    $scope.visibleList = getVisibleElements();

    $scope.$broadcast('stop');
    $scope.$digest();
    $scope.$broadcast('resume');
  });
});

Справочный документ: https://coderwall.com/p/d_aisq/speeding-up-angularjs-s-digest-loop

Спасибо.

Ответ 2

Это хороший вопрос и подчеркивает один из самых больших недостатков Angular 1.x. Существует мало контроля над тем, как управляется цикл дайджест. Он предназначен для использования в черном ящике и для более крупных приложений, что может привести к серьезным проблемам с производительностью. Нет способа Angular делать то, что вы предлагаете, но есть что-то, что поможет вам достичь одних и тех же целей (т.е. Улучшить производительность цикла дайджеста, когда изменяется только одна вещь).

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

Идея заключается в том, что вы можете указать определенные привязки только для $digested, когда определенное событие было поднято.

Существует несколько способов использования плагина, но вот тот, который я считаю эффективным:

В файле шаблона укажите привязку с использованием специального синтаксиса привязки-уведомления:

<div>{{:user-data-change:user.name}}</div>
<div>{{:job-data-change:job.name}}</div>

Эти два привязки не будут грязно проверены на большинстве циклов дайджестов, если они не будут уведомлены.

В вашем контроллере, когда пользовательские данные меняются, сообщите об этом следующим образом:

this.refreshUserData().then(() => {
  $scope.$broadcast('$$rebind::user-data-change');
});

(и аналогичный для job-data-changed)

При этом привязки для user.name будут проверяться только в широковещательной передаче.

Несколько вещей, которые нужно иметь в виду:

  • Это существенно снижает одно из ключевых преимуществ Angular (также это основная слабость для больших приложений). Двусторонняя привязка обычно означает, что вам не нужно активно управлять изменениями в вашей модели, но при этом вы это делаете. Поэтому я бы рекомендовал использовать это для частей вашего приложения, которые имеют множество привязок и вызывают замедление.
  • $emit и $broadcast могут влиять на производительность, поэтому попробуйте вызвать их только на небольших частях дерева $scope (scope с небольшим количеством или без детей).
  • Взгляните на документацию, так как есть несколько способов использования плагина. Выберите шаблон использования, который наилучшим образом подходит для вашего приложения.

Ответ 3

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

Я бы рассмотрел рефакторинг как/что вы $watching. Возможно, использование ngModelController $viewChangeListeners было бы более подходящим, чем $watch?