Устранение неполадок Angular "10 $digest() итераций достигнуто" Ошибка

10 $digest() итераций. Aborting!

Существует много поддерживающего текста в смысле "Наблюдатели, уволенные в последних 5 итерациях" и т.д., но многие из этого текста являются Javascript-кодом из различных функций. Существуют ли правила для диагностики этой проблемы? Это проблема, которая может ВСЕГДА быть смягчена или есть приложения достаточно сложные, чтобы эта проблема рассматривалась как просто предупреждение?

Ответ 1

как сказал Вен, вы либо возвращаете разные (не идентичные) объекты в каждом цикле $digest, либо слишком часто изменяете данные.

Самое быстрое решение выяснить, какая часть вашего приложения вызывает это поведение:

  • удалить все подозрительные HTML - в основном удалить все ваши html из шаблона и проверить, нет ли предупреждений
  • если нет предупреждений - добавьте небольшие части удаляемого вами html и проверьте, не верна ли проблема.
  • повторите шаг 2, пока не получите предупреждение - вы поймете, какая часть вашего html несет ответственность за проблему.
  • исследуем далее - часть с шага 3 отвечает за либо мутирование объектов в $scope, либо возвращает неидентичные объекты в каждом цикле $digest.
  • если после шага 1 у вас все еще есть предупреждения $digest итерации, чем вы, вероятно, делаете что-то очень подозрительное. Повторите те же шаги для родительского шаблона/области/контроллера.

Вы также хотите убедиться, что вы не изменяете ввод пользовательских фильтров

Имейте в виду, что в JavaScript существуют определенные типы объектов, которые не ведут себя так, как вы обычно ожидали:

new Boolean(true) === new Boolean(true) // false
new Date(0) == new Date(0) // false
new String('a') == new String('a') // false
new Number(1) == new Number(1) // false
[] == [] // false
new Array == new Array // false
({})==({}) // false

Ответ 2

Обычно это происходит, когда вы каждый раз возвращаете другой объект.

Например, если вы используете это в ng-repeat:

$scope.getObj = function () {
  return [{a: 1}, {b: 2}];
};

Вы получите это сообщение об ошибке, потому что Angular пытается получить "стабильность" и будет выполнять функцию до тех пор, пока она не вернет тот же результат 2 раза (по сравнению с ===), что в нашем случае никогда не будет return true, потому что функция всегда возвращает новый объект.

console.log({} === {}); // false. Those are two different objects!

В этом случае вы можете исправить это, непосредственно сохраняя объект в области, например.

$scope.objData = [{a: 1}, {b: 2}];
$scope.getObj = function () {
  return $scope.objData;
};

Таким образом, вы всегда возвращаете один и тот же объект!

console.log($scope.objData === $scope.objData); // true (a bit obvious...)

(Вы никогда не должны сталкиваться с этим, даже в сложных приложениях).

Обновление: Angular добавило более подробное объяснение на своем веб-сайте.

Ответ 3

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

Я исправил его путем кэширования сгенерированного объекта при первом запросе, а затем всегда возвращал кеш, если он существовал. Также был добавлен метод dirty(), который по мере необходимости уничтожал результаты кэширования.

У меня было что-то вроде этого:

function MyObj() {
    var myObj = this;
    Object.defineProperty(myObj, "computedProperty" {
        get: function () {
            var retObj = {};

            return retObj;
        }
    });
}

И здесь с реализованным решением:

function MyObj() {
    var myObj = this,
        _cached;
    Object.defineProperty(myObj, "computedProperty" {
        get: function () {
            if ( !_cached ) {
                _cached = {};
            }

            return _cached;
        }
    });

    myObj.dirty = function () {
        _cached = null;
    }
}

Ответ 4

У меня была та же проблема: я каждый раз создавал новую дату. Поэтому для тех, кто имеет дело с датами, я конвертировал все вызовы, подобные этому:

var date = new Date(); // typeof returns object

в

var date = new Date().getTime(); // typeof returns number

Инициализация номера вместо объекта даты решила его для меня.

Ответ 5

Также существует возможность того, что он не является бесконечным циклом. 10 итераций не является достаточно большим числом, чтобы заключить, что с любой достоверностью. Поэтому, прежде чем отправиться в погоню за дикими гусями, может быть целесообразно сначала исключить эту возможность.

Самый простой способ сделать это - увеличить максимальное количество циклов дайджеста до гораздо большего числа, что можно сделать в module.config метод, используя метод $rootScopeProvider.digestTtl(limit). Если ошибка infdig больше не отображается, вы просто имеете достаточно сложную логику обновления.

Если вы создаете данные или представления, основанные на рекурсивных часах, вы можете искать итеративные решения (т.е. не полагаться на новые циклы дайджеста, которые нужно запустить), используя while, for или Array.forEach. Иногда структура просто сильно вложенна и даже не рекурсивна, вероятно, не так много сделать в тех случаях, за исключением повышения предела.

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

Если вы, например, имеете свойство, которое модифицировано в $watch на себе, легко видеть, что значение изменяется бесконечно:

$scope.vm.value1 = true;
$scope.$watch("vm.value1", function(newValue)
{
    $scope.vm.value1 = !newValue;
});
[
   [
      {
         "msg":"vm.value1",
         "newVal":true,
         "oldVal":false
      }
   ],
   [
      {
         "msg":"vm.value1",
         "newVal":false,
         "oldVal":true
      }
   ],
   [
      {
         "msg":"vm.value1",
         "newVal":true,
         "oldVal":false
      }
   ],
   [
      {
         "msg":"vm.value1",
         "newVal":false,
         "oldVal":true
      }
   ],
   [
      {
         "msg":"vm.value1",
         "newVal":true,
         "oldVal":false
      }
   ]
]

Конечно, в более крупном проекте это может быть не так просто, тем более что поле msg часто имеет значение "fn: regularInterceptedExpression", если часы являются интерполяцией {{ }}.

Помимо этого, конечно, полезны уже упомянутые методы, такие как сокращение HTML-кода, чтобы найти источник проблемы.

Ответ 7

простой способ: используйте angular.js, а не файл min. откройте его и найдите строку:

if ((dirty || asyncQueue.length) && !(ttl--)) {

добавить строку ниже:

console.log("aaaa",watch)

а затем обновите свою страницу, в консоли инструментов разработки вы найдите код ошибки.

Ответ 8

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

/* @ngInject */
function topNav() {
    var directive = {
        bindToController: true,
        controller: TopNavController,
        controllerAs: 'vm',
        restrict: 'EA',
        scope: {
            'navline': '=',
            'sign': '='
        },
        templateUrl: 'app/shared/layout/top-navTHIS-IS-A-TYPO.html'
    };

Посмотрите на вкладке "Сеть" инструментов вашего веб-браузера и посмотрите, не имеет ли какой-либо ресурс ошибка 404.

Легко упускать из виду, поскольку сообщение об ошибке очень загадочно и, по-видимому, не связано с реальной проблемой.

Ответ 9

У меня была эта проблема в моем проекте, потому что в .otherwise() отсутствовало мое определение маршрута, и я попал в неправильный маршрут.

Ответ 10

У меня была эта проблема, потому что я делал это

var variableExpense = this.lodash.find(product.variableExpenseList, (ve) => {
               return ve.rawMaterial.id = rawMaterial.id;
});

Вместо этого: (notice = vs ===), мой unit test начал ломаться, и я нашел свою тупость

var variableExpense = this.lodash.find(product.variableExpenseList, (ve) => {
               return ve.rawMaterial.id === rawMaterial.id;
});

Ответ 11

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

$ctrl.myObj = {
    Title: 'my title',
    A: 'first part of dynamic toolip',
    B: 'second part of dynamic tooltip',
    C: 'some other value',
    getTooltip: function () {
        // cache the tooltip
        var obj = this;
        var tooltip = '<strong>A: </strong>' + obj.A + '<br><strong>B: </strong>' + obj.B;
        var $tooltip = {
            raw: tooltip,
            trusted: $sce.trustAsHtml(tooltip)
        };
        if (!obj.$tooltip) obj.$tooltip = $tooltip;
        else if (obj.$tooltip.raw !== tooltip) obj.$tooltip = $tooltip;
        return obj.$tooltip;
    }
};

Затем в html я обратился к нему следующим образом:

<input type="text" ng-model="$ctrl.myObj.C" uib-tooltip-html="$ctrl.myObj.getTooltip().trusted">

Ответ 12

вот как я подошел к нему и нашел решение: я проверил текст, он показал:

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!

Наблюдатели сработали за последние 5 итераций: [[{"msg": "оператор === statment && functionCall()", "newVal": [{"id": 7287, "referen...

так что если вы можете увидеть

тзд

что устав порождает ошибку. Я проверил функцию, вызванную в этом сообщении, я возвратил (false) от всех из них, просто чтобы определить, какая из них имеет проблему. один из них вызывал функцию, которая постоянно изменяет возвращаемый результат, что является проблемой.

Ответ 13

Как сумасшедший, как это звучит, я исправил эту ошибку, просто перезапустив мой браузер, когда он только что появился внезапно.

Итак, одно решение - просто очистить кеш браузера или попробовать перезапустить браузер.