jak powiedział Ven, albo zwracasz różne (nie identyczne) obiekty w każdym $digest
cyklu, albo zbyt wiele razy zmieniasz dane.
Najszybszym sposobem ustalenia, która część aplikacji powoduje takie zachowanie, jest:
- usuń cały podejrzany kod HTML - po prostu usuń cały kod HTML z szablonu i sprawdź, czy nie ma żadnych ostrzeżeń
- jeśli nie ma ostrzeżeń - dodaj małe fragmenty usuniętego kodu HTML i sprawdź, czy problem wrócił
- powtarzaj krok 2, aż pojawi się ostrzeżenie - dowiesz się, która część Twojego html jest odpowiedzialna za problem
- zbadaj dalej - część z kroku 3 jest odpowiedzialna za mutację obiektów na
$scope
lub zwraca nieidentyczne obiekty w każdym $digest
cyklu.
- jeśli nadal masz
$digest
ostrzeżenia o iteracji po kroku 1, prawdopodobnie robisz coś bardzo podejrzanego. Powtórz te same kroki dla szablonu / zakresu / kontrolera nadrzędnego
Chcesz się również upewnić, że nie zmieniasz danych wejściowych własnych filtrów
Pamiętaj, że w JavaScript istnieją określone typy obiektów, które nie zachowują się tak, jak można by się normalnie spodziewać:
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
map()
agroupBy()
potem upewnij się, że twoje ES$watch
wykonują brudne sprawdzanie,objectEquality
$watch('myFunctionDoingGropby',callback,true)
patrz docs.angularjs.org/api/ng.$rootScope.Scope#$watch$scope
której przypisywana jest_.map
lista -ed - ale w ogólnym przypadku, jak wpłynąłbyś na wspomniane brudne sprawdzanie przez równość obiektów, jeśli to nie jest ręcznie utworzony,$watch
który się potyka, alengRepeat
?Zwykle dzieje się tak, gdy za każdym razem zwracasz inny obiekt.
Na przykład, jeśli używasz tego w
ng-repeat
:$scope.getObj = function () { return [{a: 1}, {b: 2}]; };
Otrzymasz ten komunikat o błędzie, ponieważ Angular stara się mieć „stabilność” i będzie wykonywał funkcję, dopóki nie zwróci tego samego wyniku 2 razy (w porównaniu z
===
), co w naszym przypadku nigdy nie zwróci true, ponieważ funkcja zawsze zwraca wartość nowy obiekt.console.log({} === {}); // false. Those are two different objects!
W takim przypadku możesz to naprawić, zapisując obiekt bezpośrednio w zasięgu, np
$scope.objData = [{a: 1}, {b: 2}]; $scope.getObj = function () { return $scope.objData; };
W ten sposób zawsze zwracasz ten sam obiekt!
console.log($scope.objData === $scope.objData); // true (a bit obvious...)
(Nigdy nie powinieneś się z tym spotkać, nawet w przypadku złożonych aplikacji).
Aktualizacja: Angular dodał bardziej szczegółowe wyjaśnienie na swojej stronie internetowej .
źródło
Chciałem tylko wrzucić to rozwiązanie tutaj, mam nadzieję, że pomoże innym. Otrzymałem ten problem z iteracją, ponieważ iterowałem po wygenerowanej właściwości, która tworzyła nowy obiekt za każdym razem, gdy był wywoływany.
Naprawiłem to, zapisując w pamięci podręcznej wygenerowany obiekt przy pierwszym żądaniu, a następnie zawsze zwracając pamięć podręczną, jeśli istniała. Dodano również metodę dirty (), która w razie potrzeby niszczyłaby buforowane wyniki.
Miałem coś takiego:
function MyObj() { var myObj = this; Object.defineProperty(myObj, "computedProperty" { get: function () { var retObj = {}; return retObj; } }); }
A oto z wdrożonym rozwiązaniem:
function MyObj() { var myObj = this, _cached; Object.defineProperty(myObj, "computedProperty" { get: function () { if ( !_cached ) { _cached = {}; } return _cached; } }); myObj.dirty = function () { _cached = null; } }
źródło
Istnieje również możliwość, że w ogóle nie będzie to nieskończona pętla. 10 iteracji nie jest wystarczająco dużą liczbą, aby stwierdzić to z jakąkolwiek pewnością. Dlatego przed wyruszeniem w pogoń za dziką gęsią warto najpierw wykluczyć tę możliwość.
Najłatwiejszą metodą jest zwiększenie maksymalnej liczby pętli skrótu do znacznie większej liczby, co można zrobić w
module.config
metodzie, używając$rootScopeProvider.digestTtl(limit)
metody. Jeśliinfdig
błąd już się nie pojawia, masz po prostu wystarczająco złożoną logikę aktualizacji.Jeśli budować danych lub widoków zależnych od rekurencyjnych zegarków może chcesz szukać rozwiązań iteracyjnych (czyli nie opierając się na nowych strawić pętli zostać uruchomiona) używając
while
,for
lubArray.forEach
. Czasami struktura jest po prostu silnie zagnieżdżona, a nawet nie rekursywna, prawdopodobnie w takich przypadkach nie ma wiele do zrobienia poza podniesieniem limitu.Inną metodą debugowania błędu jest sprawdzenie danych skrótu. Jeśli dobrze wydrukujesz JSON, otrzymasz tablicę tablic. Każdy wpis najwyższego poziomu reprezentuje iterację, każda iteracja składa się z listy obserwowanych wpisów.
Jeśli na przykład masz właściwość, która została zmodyfikowana w
$watch
samym sobie, łatwo zauważyć, że wartość zmienia się w nieskończoność:$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 } ] ]
Oczywiście w większych projektach może to nie być takie proste, zwłaszcza że
msg
pole często ma wartość,"fn: regularInterceptedExpression"
jeśli zegarek jest{{ }}
interpolowany.Poza tym wspomniane już metody, takie jak wycinanie kodu HTML w celu znalezienia źródła problemu, są oczywiście pomocne.
źródło
Miałem ten sam problem - za każdym razem tworzyłem nową datę. Więc dla każdego, kto ma do czynienia z datami, przekonwertowałem wszystkie połączenia w ten sposób:
var date = new Date(); // typeof returns object
do:
var date = new Date().getTime(); // typeof returns number
Zainicjowanie liczby zamiast obiektu daty rozwiązało to za mnie.
źródło
Prosty sposób: użyj pliku angular.js, a nie pliku min. otwórz go i znajdź linię:
if ((dirty || asyncQueue.length) && !(ttl--)) {
dodaj wiersz poniżej:
console.log("aaaa",watch)
a następnie odśwież stronę, w konsoli narzędzi programistycznych znajdziesz kod błędu.
źródło
To znany błąd
ui-router
, który nam pomógł: https://github.com/angular-ui/ui-router/issues/600źródło
Chciałbym również wspomnieć, że otrzymałem ten komunikat o błędzie, gdy miałem literówkę w templateUrl niestandardowej dyrektywy, którą miałem w moim projekcie. Z powodu literówki nie można załadować szablonu.
/* @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' };
Spójrz na kartę sieciową narzędzi programistycznych swojej przeglądarki internetowej i sprawdź, czy któryś zasób ma błąd 404.
Łatwo przeoczyć, ponieważ komunikat o błędzie jest bardzo tajemniczy i pozornie niezwiązany z rzeczywistym problemem.
źródło
Miałem ten problem w moim projekcie, ponieważ .otherwise () nie zawierało mojej definicji trasy i trafiałem na złą trasę.
źródło
Miałem ten problem, ponieważ to robiłem
var variableExpense = this.lodash.find(product.variableExpenseList, (ve) => { return ve.rawMaterial.id = rawMaterial.id; });
Zamiast tego: (uwaga = vs ===), mój test jednostkowy zaczął się psuć i znalazłem swoją głupotę
var variableExpense = this.lodash.find(product.variableExpenseList, (ve) => { return ve.rawMaterial.id === rawMaterial.id; });
źródło
Natknąłem się na ten problem, w którym potrzebowałem dynamicznej podpowiedzi ... spowodowało to, że angular przeliczył ją za każdym razem jako nową wartość (mimo że była taka sama). Utworzyłem funkcję do buforowania obliczonej wartości w następujący sposób:
$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; } };
Następnie w html uzyskałem do niego dostęp w ten sposób:
<input type="text" ng-model="$ctrl.myObj.C" uib-tooltip-html="$ctrl.myObj.getTooltip().trusted">
źródło
tak podszedłem do tego i znalazłem rozwiązanie: sprawdziłem tekst, pokazał:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Obserwatorzy uruchomieni w ostatnich 5 iteracjach: [[{"msg": "statement === statment && functionCall ()", "newVal": [{"id": 7287, "odwołanie ...
więc jeśli widzisz plik
to jest instrukcja powodująca błąd. Sprawdziłem funkcję wywołaną w tej wiadomości, zwróciłem (false) z nich wszystkich tylko po to, aby określić, który z nich ma problem. jeden z nich wywoływał funkcję, która ciągle zmienia wartość powrotu, co jest problemem.
źródło
Choć brzmi to szalenie, naprawiłem ten błąd, po prostu ponownie uruchamiając przeglądarkę, gdy nagle się pojawiła.
Jednym z rozwiązań jest po prostu wyczyszczenie pamięci podręcznej przeglądarki lub próba ponownego uruchomienia przeglądarki.
źródło