$ apply sudah dalam error progres

133

Jejak tumpukan:

Error: $apply already in progress
at Error (<anonymous>)
at beginPhase (file:///android_asset/www/built.min.js:7:22740)
at Object.Scope.$apply (file:///android_asset/www/built.min.js:7:25967)
at navigator.geolocation.getCurrentPosition.that (file:///android_asset/www/built.min.js:13:8670)
at Object.geolocation.getCurrentPosition (file:///android_asset/www/plugins/org.apache.cordova.core.geolocation/www/geolocation.js:122:13)
at Object.getCurrentPosition (file:///android_asset/www/built.min.js:13:8589)
at Object.getCurrentPosition (file:///android_asset/www/built.min.js:13:8277)
at Object.getCurrentCity (file:///android_asset/www/built.min.js:13:8941)
at Object.$scope.locateDevice (file:///android_asset/www/built.min.js:13:10480)
at file:///android_asset/www/built.min.js:7:12292:7

merujuk pada kode ini http://pastebin.com/B9V6yvFu

    getCurrentPosition: cordovaReady(function (onSuccess, onError, options) {

        navigator.geolocation.getCurrentPosition(function () {
            var that = this,
                args = arguments;

            if (onSuccess) {
                $rootScope.$apply(function () {
                    onSuccess.apply(that, args);
                });
            }
        }, function () {
            var that = this,
                args = arguments;
            if (onError) {
                $rootScope.$apply(function () {
                    onError.apply(that, args);
                });
            }
        }, {
            enableHighAccuracy: true,
            timeout: 20000,
            maximumAge: 18000000
        });
    })

Anehnya, pada LG4X saya berfungsi dengan baik, namun pada samsung s2 saya melempar kesalahan di atas. Ada ide apa yang salah?

Suara positif
sumber
1
Sudahkah Anda mencoba stackoverflow.com/a/12859093/1266600 ? Mungkin karena perangkat yang berbeda -> kecepatan pemrosesan yang berbeda -> pengaturan waktu yang berbeda, yang dapat menyebabkan konflik di beberapa tempat tetapi tidak di tempat lain.
sushain97
20
use$timeout()
Onur Yıldırım
7
Beri +1 ke komentar $ timeout (). Lihat: stackoverflow.com/questions/12729122/…
Trevor

Jawaban:

106

Anda mendapatkan kesalahan ini karena Anda menelepon $apply siklus pencernaan yang ada.

Pertanyaan besarnya adalah: mengapa Anda menelepon $apply? Anda seharusnya tidak perlu menelepon $applykecuali Anda berinteraksi dari acara non-Angular. Keberadaan$apply biasanya berarti saya melakukan sesuatu yang salah (kecuali, sekali lagi, $ berlaku terjadi dari peristiwa non-Angular).

Jika $apply benar-benar sesuai di sini, pertimbangkan untuk menggunakan pendekatan "terapkan aman":

https://coderwall.com/p/ngisma

Brian Genisio
sumber
41
Inti dari safe safe yang diterapkan adalah anti-pola (menurut dokumen) github.com/angular/angular.js/wiki/Anti-Patterns . Jika Anda ingin cara yang didukung di masa depan (fase $$ akan hilang!), Bungkus kode Anda dalam $ timeout () tanpa waktu yang ditetapkan. Ini akan berlaku dengan aman setelah siklus intisari selesai.
betaorbust
@betaorbust Setuju. Berlaku aman itu buruk. Selain itu, menelepon terlalu sering berlaku dapat menyebabkan masalah kinerja. Cara terbaik adalah menyusun kode untuk menghindari masalah secara bersamaan.
Brian Genisio
Saya tidak menelepon berlaku
sirkuit
41

Anda dapat menggunakan pernyataan ini:

if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest') {
    $scope.$apply();
}
Dariraze
sumber
1
Tidak disarankan untuk menggunakan variabel yang dimulai dengan $$ karena sifatnya pribadi. Dalam hal ini fase $$
Ara Yeressian
9
Jawaban ini jauh lebih bermanfaat daripada yang di atas. Saya butuh solusi, bukan untuk dinasihati untuk sesuatu yang mungkin di luar kendali saya. Kami memiliki campuran kode sudut dan warisan, dan mereka harus berinteraksi entah bagaimana. Terlalu mahal untuk hanya menulis ulang semua kode warisan ...
Jordan Lapp
24

Jika lingkup harus diterapkan dalam beberapa kasus, maka Anda dapat mengatur batas waktu sehingga $ berlaku ditangguhkan hingga centang selanjutnya

setTimeout(function(){ scope.$apply(); });

atau bungkus kode Anda dalam $ timeout (function () {..}); karena $ secara otomatis akan menerapkan lingkup di akhir eksekusi. Jika Anda membutuhkan fungsi Anda untuk berperilaku sinkron, saya akan melakukan yang pertama.

jeff.d
sumber
Saya menemukan bahwa saya perlu memasukkan tindakan dalam setTimeout(function() { $apply(function() {... do stuff ...} ) })Vendhan per @ Tamil di bawah ini.
prototipe
6
Jangan gunakan setTimeout, itu hanya menciptakan kebutuhan untuk $ lainnya berlaku. Gunakan framework, ia memiliki layanan $ timeout yang melakukan semua itu untuk Anda.
Spencer
10

Dalam kasus saya, saya menggunakan $applydengan UI kalender sudut untuk menautkan beberapa acara:

$scope.eventClick = function(event){           
    $scope.$apply( function() {
        $location.path('/event/' + event.id);
    });
};

Setelah membaca dokumen masalah: https://docs.angularjs.org/error/ $ rootScope / inprog

Bagian Inconsistent API (Sync / Async) sangat menarik:

Misalnya, bayangkan perpustakaan pihak ke-3 yang memiliki metode yang akan mengambil data untuk kita. Karena mungkin membuat panggilan tidak sinkron ke server, itu menerima fungsi panggilan balik, yang akan dipanggil ketika data tiba.

Karena, konstruktor MyController selalu dipakai dari dalam panggilan $ apply, handler kami mencoba memasukkan blok $ apply baru dari dalam satu.

Saya mengubah kode menjadi:

$scope.eventClick = function(event){           
    $timeout(function() {
        $location.path('/event/' + event.id);
    }, 0);
};

Bekerja seperti pesona!

Di sini kami telah menggunakan $ timeout untuk menjadwalkan perubahan pada cakupan di tumpukan panggilan mendatang. Dengan memberikan periode waktu habis 0ms, ini akan terjadi sesegera mungkin dan $ timeout akan memastikan bahwa kode akan dipanggil dalam satu blok $ apply tunggal.

mpgn
sumber
1
Solusi $ timeout delay 0 Anda mengagumkan.
Ahsan
9

Di sudut 1.3, saya pikir, mereka menambahkan fungsi baru - $scope.$applyAsync(). Panggilan fungsi ini berlaku nanti - setidaknya sekitar 10 ms. Ini tidak sempurna, tetapi setidaknya menghilangkan kesalahan yang mengganggu.

https://docs.angularjs.org/api/ng/type/ $ rootScope.Scope # $ applyAsync

pengguna3413723
sumber
3

Kapan pun, hanya ada satu $digestatau $applyoperasi yang sedang berjalan. Ini untuk mencegah sangat sulit mendeteksi bug memasuki aplikasi Anda. Tumpukan jejak kesalahan ini memungkinkan Anda untuk melacak asal dari saat ini melaksanakan $applyatau$digest panggilan , yang menyebabkan kesalahan.

Info lebih lanjut: https://docs.angularjs.org/error/$rootScope/inprog?p0=$apply

lupa
sumber
2

Baru saja menyelesaikan masalah ini. Ini didokumentasikan di sini .

Saya menelepon $rootScope.$applydua kali dalam aliran yang sama. Yang saya lakukan adalah membungkus isi fungsi layanan dengan a setTimeout(func, 1).


sumber
1

Saya tahu ini pertanyaan lama tetapi jika Anda benar-benar perlu menggunakan $ scope. $ ApplyAsync ();

akaco
sumber
0

Saya memanggil $ scope. $ Berlaku seperti ini untuk mengabaikan panggilan berulang dalam satu kali.

      var callApplyTimeout = null;
      function callApply(callback) {
          if (!callback) callback = function () { };
          if (callApplyTimeout) $timeout.cancel(callApplyTimeout);

          callApplyTimeout = $timeout(function () {
              callback();
              $scope.$apply();
              var d = new Date();
              var m = d.getMilliseconds();
              console.log('$scope.$apply(); call ' + d.toString() + ' ' + m);
          }, 300);
      }

cukup telepon

callApply();
Marosdee Uma
sumber