Cara Mengatasi Masalah Angular Kesalahan “10 $ digest () iterasi tercapai”


91

10 $ digest () iterasi tercapai. Membatalkan!

Ada banyak teks pendukung dalam arti "Pengamat ditembakkan dalam 5 iterasi terakhir:", dll., Tetapi banyak teks ini merupakan kode Javascript dari berbagai fungsi. Apakah ada aturan praktis untuk mendiagnosis masalah ini? Apakah ini masalah yang SELALU dapat diatasi, atau apakah ada aplikasi yang cukup kompleks sehingga masalah ini harus diperlakukan hanya sebagai peringatan?

Jawaban:


80

seperti yang dikatakan Ven, Anda mengembalikan objek yang berbeda (tidak identik) pada setiap $digestsiklus, atau Anda terlalu sering mengubah data.

Solusi tercepat untuk mengetahui bagian mana dari aplikasi Anda yang menyebabkan perilaku ini adalah:

  1. hapus semua HTML yang mencurigakan - pada dasarnya hapus semua html Anda dari template, dan periksa apakah tidak ada peringatan
  2. jika tidak ada peringatan - tambahkan bagian kecil dari html yang Anda hapus dan periksa apakah masalahnya kembali
  3. ulangi langkah 2 hingga Anda mendapatkan peringatan - Anda akan mengetahui bagian mana dari html Anda yang bertanggung jawab atas masalah tersebut
  4. menyelidiki lebih lanjut - bagian dari langkah 3 bertanggung jawab untuk mutasi objek pada $scopeatau mengembalikan objek non-identik pada setiap $digestsiklus.
  5. jika Anda masih memiliki $digestperingatan iterasi setelah langkah 1, Anda mungkin melakukan sesuatu yang sangat mencurigakan. Ulangi langkah yang sama untuk template induk / scope / controller

Anda juga ingin memastikan Anda tidak mengubah masukan filter kustom Anda

Perlu diingat, bahwa di JavaScript ada jenis objek tertentu yang tidak berperilaku seperti yang biasanya Anda harapkan:

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
Terima kasih! Ini adalah heuristik yang membantu. Saya juga berpikir bahwa fitur "track by" Angular untuk ngRepeat juga akan membantu saya. Saya melakukan beberapa hal map () dan groupBy () menggunakan Underscore dalam sebuah layanan, jadi pasti mengembalikan objek "berbeda" setiap kali (meskipun secara logis mewakili hal yang sama - "track by Id" akan membantu Angular tidak melihatnya sebagai "perubahan" jika belum benar-benar).
blaster

2
Jika Anda melakukan map()dan kemudian groupBy()memastikan bahwa $watches Anda melakukan pemeriksaan kotor dengan objectEquality $watch('myFunctionDoingGropby',callback,true) melihat docs.angularjs.org/api/ng.$rootScope.Scope#$watch
g00fy

Sesuai komentar di atas, "track by" memperbaiki masalah saya (lihat dokumen di sini: docs.angularjs.org/api/ng/directive/ngRepeat ). Saya akan berterima kasih atas komentar penjelasan yang menjelaskan mengapa ini berhasil ...
Soferio

@ g00fy: Itu adalah petunjuk yang baik, dan saya dapat mengganti fungsi pengambilan daftar saya dengan variabel pada saya $scopeyang diberi _.mapdaftar -ed sekali - tetapi dalam kasus umum, bagaimana Anda akan mempengaruhi pemeriksaan kotor tersebut dengan persamaan objek jika itu bukan dibuat secara manual $watchyang tersandung, tapi ngRepeat?
ATAU Mapper

73

Biasanya itu terjadi ketika Anda mengembalikan objek yang berbeda setiap saat.

Misalnya, jika Anda menggunakan ini di ng-repeat:

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

Anda akan mendapatkan pesan kesalahan ini karena Angular mencoba untuk memiliki "stabilitas" dan akan menjalankan fungsi hingga mengembalikan hasil yang sama 2 kali (dibandingkan dengan ===), yang dalam kasus kami tidak akan pernah mengembalikan nilai true karena fungsi selalu mengembalikan objek baru.

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

Dalam kasus ini, Anda dapat memperbaikinya dengan menyimpan objek dalam cakupan secara langsung, mis

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

Dengan begitu, Anda selalu mengembalikan objek yang sama!

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

(Anda tidak boleh menemukan itu, bahkan pada aplikasi yang kompleks).

Pembaruan: Angular telah menambahkan beberapa penjelasan mendalam di situs web mereka .


Bagaimana Anda menghentikan ini terjadi? Saya mengalami situasi serupa sekarang.
Penakluk

2
Pastikan Anda tidak membuat objek yang berbeda pada setiap panggilan;).
Ven

Bagaimana saya bisa memastikan ini? Saya melakukan sesuatu seperti item dalam func (obj), tetapi func tampaknya dipanggil berkali-kali daripada sekali seperti yang saya harapkan. Saya mencoba menggunakan ng-init untuk memanggil func dan kemudian melampirkannya ke model pada ruang lingkup tetapi itu juga tidak berhasil.
Penakluk

1
Ini adalah contoh yang Anda lihat di semua tempat tentang masalah ini. Akan sangat luar biasa jika Angular dapat menunjukkan fungsi yang menyinggung, yang memiliki perilaku ini ...
Jorn

1
@BenWheeler Sudah pasti membaik sejak 2013, ya: P.
Ven

11

Hanya ingin melempar solusi ini ke sini, semoga bisa membantu orang lain. Saya mendapatkan masalah iterasi ini karena saya melakukan iterasi pada properti yang dihasilkan yang membuat objek baru setiap kali dipanggil.

Saya memperbaikinya dengan meng-cache objek yang dihasilkan saat pertama kali diminta, lalu selalu mengembalikan cache jika ada. Metode dirty () juga ditambahkan, yang akan menghancurkan hasil yang di-cache sesuai kebutuhan.

Saya punya sesuatu seperti ini:

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

            return retObj;
        }
    });
}

Dan inilah solusi yang diterapkan:

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

            return _cached;
        }
    });

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

Ya Tuhan, saya berharap bisa memberi Anda 10 suara positif. Anda baru saja memecahkan masalah yang membuat saya membenturkan kepala ke dinding selama hampir 3 jam. Aku cinta kamu!
GMA

7

Ada juga kemungkinan itu tidak menjadi loop tak terbatas sama sekali. 10 iterasi bukanlah angka yang cukup besar untuk menyimpulkan dengan sejumlah kepastian. Jadi sebelum melakukan pengejaran liar, mungkin disarankan untuk mengesampingkan kemungkinan itu terlebih dahulu.

Metode termudah untuk melakukannya adalah meningkatkan jumlah loop intisari maksimum ke angka yang jauh lebih besar, yang dapat dilakukan dalam module.configmetode, menggunakan $rootScopeProvider.digestTtl(limit)metode. Jika infdigkesalahan tidak lagi muncul, Anda hanya memiliki beberapa logika pembaruan yang cukup kompleks.

Jika Anda membangun data atau tampilan dengan mengandalkan jam tangan rekursif, Anda mungkin ingin mencari solusi berulang (yaitu tidak mengandalkan loop intisari baru untuk memulai) menggunakan while, foratau Array.forEach. Terkadang strukturnya sangat bersarang dan bahkan tidak rekursif, mungkin tidak banyak yang harus dilakukan dalam kasus tersebut kecuali menaikkan batas.

Metode lain untuk men-debug kesalahan adalah melihat data intisari. Jika Anda cukup mencetak JSON, Anda mendapatkan array array. Setiap entri tingkat atas mewakili sebuah iterasi, setiap iterasi terdiri dari daftar entri arloji.

Misalnya, jika Anda memiliki properti yang dimodifikasi dengan $watchon sendiri, mudah untuk melihat bahwa nilainya berubah tanpa batas:

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

Tentu saja dalam proyek yang lebih besar ini mungkin tidak sesederhana itu, terutama karena msgbidang sering memiliki nilai "fn: regularInterceptedExpression"jika jam tangan adalah {{ }}interpolasi.

Selain itu, metode yang telah disebutkan, seperti memotong HTML untuk menemukan sumber masalah, tentu saja membantu.


6

Saya memiliki masalah yang sama - saya membuat tanggal baru setiap saat. Jadi bagi siapa pun yang berurusan dengan tanggal, saya mengubah semua panggilan seperti ini:

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

untuk:

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

Menginisialisasi angka alih-alih objek tanggal memecahkannya untuk saya.


2

cara mudahnya adalah: gunakan angular.js, bukan file min. buka dan temukan barisnya:

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

tambahkan baris di bawah ini:

console.log("aaaa",watch)

lalu segarkan laman Anda, di konsol alat pengembangan, Anda akan menemukan kode kesalahan.



0

Saya juga ingin menyebutkan bahwa saya menerima pesan kesalahan ini ketika saya mengalami kesalahan ketik di templateUrl dari arahan kustom yang saya miliki di proyek saya. Karena salah ketik, template tidak dapat dimuat.

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

Lihat di tab jaringan alat dev browser web Anda, dan lihat apakah ada sumber daya yang mengalami kesalahan 404.

Mudah untuk dilupakan, karena pesan kesalahannya sangat samar dan tampaknya tidak berhubungan dengan masalah sebenarnya.


0

Saya mengalami masalah ini dalam proyek saya karena .otherwise () kehilangan definisi rute saya dan saya memilih rute yang salah.


0

Saya mengalami masalah ini karena saya melakukan ini

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

Alih-alih ini: (perhatikan = vs ===), tes unit saya mulai rusak dan saya menemukan kebodohan saya

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

0

Saya mengalami masalah ini di mana saya membutuhkan tooltip dinamis ... itu menyebabkan sudut menghitung ulang setiap kali sebagai nilai baru (meskipun itu sama). Saya membuat fungsi untuk menyimpan nilai yang dihitung seperti ini:

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

Kemudian di html, saya mengaksesnya seperti ini:

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

0

beginilah cara saya mendekatinya dan menemukan solusi: Saya memeriksa teksnya, itu menunjukkan:

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

Pengamat diaktifkan dalam 5 iterasi terakhir: [[{"msg": "statement === statment && functionCall ()", "newVal": [{"id": 7287, "referen ...

jadi jika Anda bisa melihat

pesan

itulah pernyataan yang menghasilkan kesalahan. Saya memeriksa fungsi yang dipanggil dalam pesan ini, saya mengembalikan (salah) dari semuanya hanya untuk menentukan mana yang bermasalah. salah satunya memanggil fungsi yang terus mengubah pengembalian, yang merupakan masalah.


-3

Kedengarannya gila, saya memperbaiki kesalahan ini hanya dengan memulai ulang browser saya ketika tiba-tiba terpotong.

Jadi salah satu solusinya adalah dengan menghapus cache browser Anda atau mencoba memulai ulang browser.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.