Açısal "10 $ Digest () yinelemeye ulaşıldı" Hatası Nasıl Giderilir?


91

10 $ özet () yinelemesine ulaşıldı. İptal ediliyor!

"Son 5 yinelemede ateşlenen gözlemciler:" vb. Anlamında pek çok destekleyici metin var, ancak bu metnin çoğu çeşitli işlevlerden Javascript kodudur. Bu sorunu teşhis etmek için pratik kurallar var mı? HER ZAMAN hafifletilebilecek bir sorun mu yoksa bu sorunun yalnızca bir uyarı olarak ele alınması gereken yeterince karmaşık uygulamalar var mı?

Yanıtlar:


80

Ven'in dediği gibi, ya her $digestdöngüde farklı (özdeş olmayan) nesneler döndürüyorsunuz ya da verileri çok fazla değiştiriyorsunuz.

Uygulamanızın hangi bölümünün bu davranışa neden olduğunu anlamanın en hızlı çözümü şudur:

  1. tüm şüpheli HTML'yi kaldırın - temel olarak tüm html'nizi şablondan kaldırın ve uyarı olup olmadığını kontrol edin
  2. uyarı yoksa - kaldırdığınız html'nin küçük parçalarını ekleyin ve sorunun geri gelip gelmediğini kontrol edin
  3. 2. adımı bir uyarı alana kadar tekrarlayın - sorundan html'nizin hangi bölümünün sorumlu olduğunu anlayacaksınız
  4. daha fazla araştırın - 3. adımdaki kısım, nesnelerin değiştirilmesinden $scopeveya her $digestdöngüde aynı olmayan nesneleri döndürmekten sorumludur .
  5. $digest1. adımdan sonra hala yineleme uyarıları alıyorsanız , muhtemelen çok şüpheli bir şey yapıyorsunuz demektir. Üst şablon / kapsam / denetleyici için aynı adımları tekrarlayın

Ayrıca, özel filtrelerinizin girişini değiştirmediğinizden emin olmak istersiniz.

JavaScript'te normalde beklediğiniz gibi davranmayan belirli nesne türleri olduğunu unutmayın:

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
Teşekkür ederim! Bu yararlı bir buluşsal yöntemdir. Ayrıca Angular'ın ngRepeat için yeni "takip etme" özelliğinin bana da yardımcı olacağını düşünüyorum. Bir hizmette Alt Çizgi kullanarak bazı map () ve groupBy () şeyler yapıyorum, bu nedenle her seferinde kesinlikle "farklı" nesneler döndürüyor (mantıksal olarak aynı şeyleri temsil etseler bile - "kimliğe göre izleme" Angular'ın onları görmemesine yardımcı olur gerçekten yapmamışlarsa bir "değişiklik" olarak).
blaster

2
Eğer yapıyorsanız map()ve groupBy()marka shure daha da o $watches tarafından kirli denetlemesi uygulayarak objectEquality $watch('myFunctionDoingGropby',callback,true) bkz docs.angularjs.org/api/ng.$rootScope.Scope#$watch
g00fy

Yukarıdaki yoruma göre, sorunumu "takip etme" sorunu çözdü (buradaki belgelere bakın: docs.angularjs.org/api/ng/directive/ngRepeat ). Bunun neden işe yaradığını açıklayan bir yorum için minnettar
olurum

@ g00fy: Bu iyi bir ipucuydu ve liste alma işlevimi $scope, _.map-ed listeye bir kez atanan bir değişkenle değiştirebildim - ancak genel durumda, söz konusu kirli kontrolü nesne eşitliği ile nasıl etkilerdiniz? manuel olarak yaratılmış değil $watch, ama ngRepeat?
VEYA Mapper

73

Bu genellikle her seferinde farklı bir nesneyi iade ettiğinizde olur.

Örneğin, bunu bir ng-repeat:

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

Bu hata mesajını alacaksınız çünkü Angular "kararlılığa" sahip olmaya çalışır ve aynı sonucu 2 kez (ile karşılaştırarak ===) döndürene kadar işlevi yürütür , bu bizim durumumuzda asla doğru dönmez çünkü işlev her zaman bir yeni nesne.

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

Bu durumda, nesneyi doğrudan kapsamda saklayarak düzeltebilirsiniz, örn.

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

Bu şekilde her zaman aynı nesneyi iade edersiniz!

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

(Karmaşık uygulamalarda bile bununla asla karşılaşmamalısınız).

Güncelleme: Angular , web sitesine biraz daha derinlemesine açıklama ekledi .


Bunun olmasını nasıl durdurursunuz? Şu anda benzer bir durum yaşıyorum.
Conqueror

2
Her aramada farklı nesneler oluşturmadığınızdan emin olun;).
Ven

Bunu nasıl sağlayabilirim? Func (obj) 'de item gibi bir şey yapıyorum, ancak func umduğum gibi birçok kez çağrılıyor gibi görünüyor. Func'u çağırmak için ng-init'i kullanmayı denedim ve ardından onu kapsamdaki bir modele eklemeye çalıştım ama bu da işe yaramadı.
Fatih

1
Bu problemin her yerinde gördüğünüz örnek budur. Angular, rahatsız edici işlevi işaret edebilseydi, bu davranışa sahip ...
Jorn

1
@BenWheeler 2013'ten beri kesinlikle gelişti, evet: P.
Ven

11

Sadece bu çözümü buraya atmak istedim, umarım başkalarına yardımcı olur. Bu yineleme sorununu alıyordum çünkü her çağrıldığında yeni bir nesne oluşturan, oluşturulmuş bir özelliği yineliyordum.

Üretilen nesneyi ilk istendiğinde önbelleğe alarak ve ardından varsa önbelleği her zaman döndürerek düzelttim. Gerektiğinde önbelleğe alınan sonuçları yok edecek bir dirty () yöntemi de eklendi.

Bende bunun gibi bir şey vardı:

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

            return retObj;
        }
    });
}

Ve işte uygulanan çözüm ile:

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

            return _cached;
        }
    });

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

Aman tanrım, keşke sana 10 ek oy verebilseydim. Yaklaşık 3 saat boyunca kafamı duvara vurmama neden olan bir sorunu çözdün. Seni seviyorum!
GMA

7

Ayrıca sonsuz bir döngü olmaması ihtimali de var. 10 yineleme, bunu herhangi bir kesinlik ile sonuçlandırmak için yeterince büyük bir sayı değildir. Bu nedenle, bir yaban kazı avına çıkmadan önce bu olasılığı göz ardı etmeniz tavsiye edilebilir.

Bunu yapmanın en kolay yöntemi, maksimum özet döngü sayısını çok daha büyük bir sayıya çıkarmaktır, bu module.configyöntem kullanılarak $rootScopeProvider.digestTtl(limit)yöntemde yapılabilir. Eğer infdighata artık görünmüyor sadece bazı yeterince karmaşık güncelleme mantığı var.

Özyinelemeli saatlere dayanarak veri veya görünümler oluşturursanız while, forveya kullanarak yinelemeli çözümler aramak isteyebilirsiniz (yani , başlatılacak yeni özet döngülerine güvenmeden) Array.forEach. Bazen yapı çok iç içe geçmiş durumdadır ve hatta yinelemeli bile değildir, bu durumlarda muhtemelen limiti yükseltmek dışında yapılacak çok şey yoktur.

Hatayı ayıklamanın başka bir yöntemi de özet verilere bakmaktır. JSON'u oldukça yazdırırsanız, bir dizi dizi elde edersiniz. Her bir üst düzey giriş bir yinelemeyi temsil eder, her yineleme, izleme girişlerinin bir listesinden oluşur.

Örneğin $watch, kendi içinde değiştirilmiş bir özelliğiniz varsa , değerin sonsuz bir şekilde değiştiğini görmek kolaydır:

$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
      }
   ]
]

Elbette daha büyük bir projede bu o kadar basit olmayabilir, özellikle de saatin interpolasyon olması durumunda msgalanın değeri genellikle vardır ."fn: regularInterceptedExpression"{{ }}

Bunun dışında, sorunun kaynağını bulmak için HTML'yi kesmek gibi daha önce bahsedilen yöntemler elbette faydalıdır.


6

Aynı sorunu yaşadım - her seferinde yeni bir tarih oluşturuyordum. Bu yüzden tarihlerle ilgilenen herkes için tüm aramaları şu şekilde dönüştürdüm:

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

to:

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

Bir tarih nesnesi yerine bir sayıyı başlatmak benim için çözdü.


2

kolay yol: min dosyası değil, angular.js kullanın. açın ve satırı bulun:

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

aşağıya satır ekleyin:

console.log("aaaa",watch)

ve ardından sayfanızı yenileyin, geliştirme araçları konsolunda hata kodunu bulacaksınız.



0

Ayrıca, projemde sahip olduğum bir özel yönergenin templateUrl'sinde bir yazım hatası olduğunda bu hata mesajını aldığımı da belirtmek isterim. Yazım hatası nedeniyle şablon yüklenemedi.

/* @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'
    };

Web tarayıcınızın geliştirme araçlarının ağ sekmesine bakın ve herhangi bir kaynakta 404 hatası olup olmadığına bakın.

Göz ardı edilmesi kolay, çünkü hata mesajı çok şifreli ve görünüşte gerçek sorunla ilgisiz.


0

Bu sorunu projemde yaşıyordum çünkü .otherwise () rota tanımımı kaçırıyordu ve yanlış rotaya vuruyordum.


0

Bu sorunu yaşadım çünkü bunu yapıyordum

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

Bunun yerine: (not = vs ===), birim testim bozulmaya başladı ve aptallığımı buldum

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

0

Dinamik bir araç ipucuna ihtiyaç duyduğum bu konuyla karşılaştım ... açısal olarak her seferinde yeni bir değer olarak yeniden hesaplamaya neden oldu (aynı olmasına rağmen). Hesaplanan değeri şu şekilde önbelleğe almak için bir işlev oluşturdum:

$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;
    }
};

Sonra html'de şöyle eriştim:

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

0

ona böyle yaklaştım ve bir çözüm buldum: Metni kontrol ettim, gösterdi:

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

Son 5 yinelemede ateşlenen izleyiciler: [[{"msg": "statement === statment && functionCall ()", "newVal": [{"id": 7287, "referen ...

yani eğer görebilirsen

msg

hatayı oluşturan ifade budur. Bu mesajda çağrılan işlevi kontrol ettim, hangisinde sorun olduğunu belirlemek için hepsinden (yanlış) döndüm. bunlardan biri geri dönüşü değiştirmeye devam eden bir işlevi çağırıyordu, sorun da bu.


-3

Kulağa çılgınca gelse de, bu hatayı sadece tarayıcımı aniden kırptığı zaman yeniden başlatarak düzelttim.

Dolayısıyla bir çözüm, tarayıcınızın önbelleğini temizlemek veya tarayıcıyı yeniden başlatmayı denemektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.