$ applica errore già in corso


133

Traccia dello stack:

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

si riferisce a questo codice 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
        });
    })

Cosa strana, sul mio LG4X funziona benissimo, tuttavia sul mio Samsung S2 genera l'errore di cui sopra. Qualche idea di cosa non va?


1
Hai provato stackoverflow.com/a/12859093/1266600 ? Potrebbe essere perché dispositivi diversi -> velocità di elaborazione diverse -> tempi diversi, che possono causare conflitti in alcuni punti ma non in altri.
sushain97,

20
use$timeout()
Onur Yıldırım,

7
+1 al commento $ timeout (). Vedi: stackoverflow.com/questions/12729122/…
Trevor

Risposte:


106

Stai ricevendo questo errore perché stai chiamando $applyall'interno di un ciclo di digestione esistente.

La grande domanda è: perché chiami $apply? Non dovresti mai aver bisogno di chiamare a $applymeno che non ti stia interfacciaendo con un evento non angolare. L'esistenza di $applysolito significa che sto facendo qualcosa di sbagliato (a meno che, di nuovo, il $ si applichi da un evento non angolare).

Se $applyè davvero appropriato qui, prendere in considerazione l'utilizzo di un approccio di "applicazione sicura":

https://coderwall.com/p/ngisma


41
Il nucleo dell'applicazione di sicurezza collegata è un anti-pattern (secondo i documenti) github.com/angular/angular.js/wiki/Anti-Patterns . Se vuoi un modo supportato dal futuro (la fase $$ sta scomparendo!) Per farlo, inserisci il tuo codice in $ timeout () senza tempo impostato. Si applicherà in modo sicuro al termine dell'attuale ciclo di digest.
betaorbust,

@betaorbust Concordato. L'applicazione sicura è negativa. Inoltre, la chiamata si applica troppe volte può causare problemi di perf. È meglio strutturare il codice per evitare il problema tutti insieme.
Brian Genisio,

non sto chiamando applicare
circuiteria


41

Puoi usare questa affermazione:

if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest') {
    $scope.$apply();
}

1
Non è consigliabile utilizzare le variabili che iniziano con $$ perché sono private. In questo caso la fase $$
Ara Yeressian,

9
Questa risposta è molto più utile di quella sopra. Ho bisogno di una soluzione, per non essere ammonito per qualcosa che potrebbe essere al di fuori del mio controllo. Abbiamo un misto di codice angolare e legacy e devono interagire in qualche modo. È troppo costoso riscrivere solo tutto il codice legacy ...
Jordan Lapp il

24

Se l'ambito deve essere applicato in alcuni casi, è possibile impostare un timeout in modo che $ apply venga rinviato al segno di spunta successivo

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

o racchiudi il tuo codice in $ timeout (function () {..}); perché applicherà automaticamente $ l'ambito alla fine dell'esecuzione. Se hai bisogno che la tua funzione si comporti in modo sincrono, farei il primo.


Ho scoperto che dovevo includere l'azione all'interno di setTimeout(function() { $apply(function() {... do stuff ...} ) })@Tamil Vendhan di seguito.
prototipo

6
Non usare setTimeout, ciò crea semplicemente la necessità di un altro $ apply. Usa il framework, ha un servizio $ timeout che fa tutto questo per te.
Spencer,

10

Nel mio caso utilizzo l' $applyinterfaccia utente del calendario angolare per collegare alcuni eventi:

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

Dopo aver letto il documento del problema: https://docs.angularjs.org/error/ $ rootScope / inprog

La parte incoerente API (Sync / Async) è molto interessante:

Ad esempio, immagina una libreria di terze parti che ha un metodo che recupererà i dati per noi. Poiché potrebbe effettuare una chiamata asincrona a un server, accetta una funzione di callback, che verrà chiamata quando arrivano i dati.

Poiché il costruttore MyController è sempre istanziato all'interno di una chiamata $ apply, il nostro gestore sta provando a inserire un nuovo blocco $ apply all'interno di una chiamata.

Cambio il codice in:

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

Funziona come un fascino!

Qui abbiamo usato $ timeout per pianificare le modifiche all'ambito in uno stack di chiamate futuro. Fornendo un periodo di timeout di 0 ms, ciò avverrà il più presto possibile e $ timeout assicurerà che il codice verrà chiamato in un singolo blocco $ apply.


1
La soluzione $ timeout delay 0 è eccezionale.
Ahsan,

9

In angolare 1.3, penso, hanno aggiunto una nuova funzione - $scope.$applyAsync(). Le chiamate di questa funzione si applicano in seguito - dicono almeno 10 ms dopo. Non è perfetto, ma almeno elimina il fastidioso errore.

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


3

In qualsiasi momento, può esserci solo una $digesto $applyoperazione in corso. Questo per evitare che errori molto difficili da rilevare entrino nella tua applicazione. La traccia dello stack di questo errore consente di tracciare l'origine dell'esecuzione $applyo della $digestchiamata attualmente in corso , che ha causato l'errore.

Maggiori informazioni: https://docs.angularjs.org/error/$rootScope/inprog?p0=$apply


2

Ho appena risolto questo problema. È documentato qui .

Stavo chiamando $rootScope.$applydue volte nello stesso flusso. Tutto quello che ho fatto è stato racchiuso il contenuto della funzione di servizio con a setTimeout(func, 1).


1

So che è una vecchia domanda, ma se hai davvero bisogno di usare $ scope. $ ApplyAsync ();


0

Chiamo $ scope. $ Si applica in questo modo per ignorare più chiamate in una volta.

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

chiama semplicemente

callApply();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.