Angular "10 $ digest () 반복에 도달했습니다"오류 문제를 해결하는 방법


91

$ digest () 반복 10 회에 도달했습니다. 중단!

"최근 5 번의 반복에서 발생한 Watchers :"등의 지원 텍스트가 많이 있지만이 텍스트의 대부분은 다양한 기능의 Javascript 코드입니다. 이 문제를 진단하기위한 경험 규칙이 있습니까? 항상 완화 할 수있는 문제입니까? 아니면이 문제를 경고로 취급해야 할 정도로 복잡한 응용 프로그램이 있습니까?

답변:


80

Ven가 말했듯이, 당신은 각 $digest주기 마다 다른 (동일하지 않은) 객체를 반환 하거나 데이터를 너무 많이 변경하고 있습니다.

앱의 어느 부분이이 동작을 일으키는 지 알아내는 가장 빠른 솔루션은 다음과 같습니다.

  1. 모든 의심스러운 HTML 제거-기본적으로 템플릿에서 모든 HTML을 제거하고 경고가 없는지 확인합니다.
  2. 경고가없는 경우-제거한 html의 작은 부분을 추가하고 문제가 다시 발생하는지 확인하십시오.
  3. 경고가 표시 될 때까지 2 단계를 반복합니다. 문제의 원인이되는 HTML 부분을 파악할 수 있습니다.
  4. 추가 조사-3 단계의 부품은 $scope$digest주기 에서 개체를 변경 하거나 동일하지 않은 개체를 반환 합니다.
  5. $digest1 단계 후에도 반복 경고 가 계속 발생하면 의심스러운 일을하고있을 것입니다. 상위 템플릿 / 범위 / 컨트롤러에 대해 동일한 단계를 반복합니다.

또한 사용자 정의 필터의 입력을 변경하지 않는지 확인하고 싶습니다.

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

5
감사합니다! 이것은 유용한 휴리스틱입니다. 또한 ngRepeat에 대한 Angular의 새로운 "추적"기능이 저에게도 도움이 될 것이라고 생각합니다. 서비스에서 Underscore를 사용하여 map () 및 groupBy () 작업을 수행하고 있으므로 매번 "다른"개체를 확실히 반환합니다 (논리적으로 동일한 것을 나타내더라도 "ID 별 추적"은 Angular가 해당 개체를 보지 못하도록 도와줍니다. 그렇지 않은 경우 "변경"으로).
블래스터

2
당신이 수행하는 경우 map()groupBy()메이크업의 SHURE보다 당신 있다는 $watch말이지으로 더러운 검사 수행 objectEquality $watch('myFunctionDoingGropby',callback,true) 참조 docs.angularjs.org/api/ng.$rootScope.Scope#$watch
g00fy

위의 의견에 따라 "track by"가 내 문제를 해결했습니다 (여기 문서 참조 : docs.angularjs.org/api/ng/directive/ngRepeat ). 내가 설명하는 설명 코멘트 감사 왜이 작품을 ...
Soferio

@ g00fy : 좋은 리드 였고, 내 목록 검색 기능을 -ed 목록에 한 번 $scope할당 된 변수로 바꿀 수 _.map있었지만 일반적으로 객체 평등에 의한 더티 검사에 어떤 영향을 미칠까요? 작동하지 않는 수동 생성 $watch이 아니지만 ngRepeat?
또는 Mapper

73

일반적으로 매번 다른 개체를 반환 할 때 발생합니다.

예를 들어 다음에서 사용하는 경우 ng-repeat:

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

Angular가 "안정성"을 가지려고하고 동일한 결과를 2 번 반환 할 때까지 (와 비교하여 ===) 함수를 실행하기 때문에이 오류 메시지가 표시됩니다.이 경우 함수가 항상 a를 반환하기 때문에 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 는 웹 사이트에 좀 더 자세한 설명을 추가했습니다 .


이것이 발생하는 것을 어떻게 막을 수 있습니까? 나는 지금 비슷한 상황을 겪고 있습니다.
Conqueror

2
호출 할 때마다 다른 객체를 생성하지 않도록하십시오.).
Ven

이것을 어떻게 확인할 수 있습니까? 나는 func (obj)의 item과 같은 것을하고 있지만 func는 내가 바라는 것처럼 한 번이 아니라 여러 번 호출되는 것 같습니다. ng-init를 사용하여 func를 호출 한 다음 스코프의 모델에 연결하려고했지만 작동하지 않았습니다.
Conqueror

1
이것은이 문제의 모든 곳에서 볼 수있는 예입니다. Angular가 문제가되는 함수를 가리킬 수 있다면 정말 멋질 것입니다.이 동작은 ...
Jorn

1
@BenWheeler 2013 년부터 확실히 개선되었습니다.
Ven

11

이 솔루션을 여기에 넣고 싶었습니다. 다른 사람들에게 도움이되기를 바랍니다. 호출 될 때마다 새 개체를 만드는 생성 된 속성을 반복했기 때문에이 반복 문제가 발생했습니다.

처음 요청했을 때 생성 된 개체를 캐싱 한 다음 항상 캐시가있는 경우 반환하여 수정했습니다. 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;
    }
}

맙소사, 10 개의 찬성표를 줄 수 있으면 좋겠어요. 당신은 제가 거의 3 시간 동안 벽에 머리를 부딪히는 문제를 해결했습니다. 사랑해!
GMA

7

또한 무한 루프가 아닐 가능성도 있습니다. 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을 자르는 것과 같은 이미 언급 한 방법이 도움이됩니다.


6

나는 똑같은 문제가 있었다-나는 매번 새로운 날짜를 만들고 있었다. 따라서 날짜를 다루는 모든 사람을 위해 다음과 같이 모든 호출을 변환했습니다.

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

에:

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

날짜 개체 대신 숫자를 초기화하면 문제가 해결되었습니다.


2

쉬운 방법은 min 파일이 아닌 angular.js를 사용하는 것입니다. 그것을 열고 줄을 찾으십시오.

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

아래에 줄 추가 :

console.log("aaaa",watch)

개발 도구 콘솔에서 페이지를 새로 고치면 오류 코드를 찾을 수 있습니다.



0

또한 내 프로젝트에있는 사용자 지정 지시문의 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 오류가있는 리소스가 있는지 확인합니다.

오류 메시지가 매우 비밀스럽고 실제 문제와 관련이없는 것처럼 보이기 때문에 간과하기 쉽습니다.


0

.otherwise () 에 내 경로 정의가 누락되어 잘못된 경로를 쳤기 때문에 프로젝트에서이 문제가 발생했습니다 .


0

이 일을했기 때문에이 문제가 발생했습니다.

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

대신에 : (notice = vs ===), 내 단위 테스트가 깨지기 시작했고 내 어리 석음을 발견했습니다.

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

0

동적 툴팁이 필요한이 문제가 발생했습니다. 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">

0

이것이 내가 접근하여 해결책을 찾은 방법입니다. 텍스트를 확인한 결과 다음과 같이 표시되었습니다.

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

최근 5 회 반복에서 발동 된 감시자 : [[{ "msg": "statement === statment && functionCall ()", "newVal": [{ "id": 7287, "참조 ...

그래서 당신이 볼 수 있다면

메시지

그것이 오류를 생성하는 문구입니다. 이 메시지에서 호출 된 함수를 확인한 후 문제가있는 항목을 확인하기 위해 모두에서 (false)를 반환했습니다. 그들 중 하나는 수익을 계속 변경하는 함수를 호출하고 있었는데 이것이 문제였습니다.


-3

미친 듯이 들리지만 갑자기 브라우저가 갑자기 잘 렸을 때 브라우저를 다시 시작하여이 오류를 수정했습니다.

따라서 한 가지 해결책은 브라우저의 캐시를 지우거나 브라우저를 다시 시작하는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.