$ Scope angular. $ Apply vs $ timeout come $ sicuro

Sto cercando di capire meglio le sfumature dell’utilizzo del servizio $ timeout in Angular come una sorta di metodo “safe $ apply”. Fondamentalmente in scenari in cui un pezzo di codice può essere eseguito in risposta a un evento angular oa un evento non angular come jQuery o qualche evento DOM standard.

Come capisco le cose:

  1. Il codice di avvolgimento in $ scope. $ Apply funziona bene per scenari in cui non si è già in un ciclo di digest (noto come evento jQuery) ma si genera un errore se è in corso un digest
  2. Il codice di avvolgimento in una chiamata $ timeout () senza nessun ritardo funziona anche se già in un ciclo di digest o no

Guardando il codice sorgente angular, sembra che $ timeout effettui una chiamata a $ rootScope. $ Apply ().

  1. Perché $ timeout () non genera anche un errore se è già in corso un ciclo di digest?
  2. La migliore pratica è usare $ scope. $ Apply () quando si è sicuri che un digest non sarà già in corso e $ timeout () quando è necessario che sia sicuro in ogni caso?
  3. $ Timeout () è davvero accettabile come “sicuro applicare” o ci sono trucchi?

Grazie per qualsiasi intuizione.

Guardando il codice sorgente angular, sembra che $ timeout effettui una chiamata a $ rootScope. $ Apply ().

  • Perché $ timeout () non genera anche un errore se è già in corso un ciclo di digest?

$timeout avvale di un $browser servizio angular non documentato. In particolare utilizza $browser.defer() che rimuove l’esecuzione della funzione in modo asincrono tramite window.setTimeout(fn, delay) , che verrà sempre eseguito al di fuori del ciclo di vita angular. Solo una volta window.setTimeout ha $rootScope.$apply() la funzione $timeout call $rootScope.$apply() .

  • La migliore pratica è usare $ scope. $ Apply () quando si è sicuri che un digest non sarà già in corso e $ timeout () quando è necessario che sia sicuro in ogni caso?

Direi così Un altro caso d’uso è che a volte è necessario accedere a una variabile $ scope che si sa sarà inizializzata solo dopo digest. Un semplice esempio potrebbe essere se si desidera impostare lo stato di un modulo su dirty all’interno del costruttore del controller (per qualsiasi motivo). Senza $ timeout il FormController non è stato inizializzato e pubblicato su $ scope, quindi il wrapping $scope.yourform.setDirty() all’interno di $ timeout assicura che FormController sia stato inizializzato. Certo, puoi fare tutto questo con una direttiva senza timeout $, dando solo un altro esempio di caso d’uso.

  • $ Timeout () è davvero accettabile come “sicuro applicare” o ci sono trucchi?

Dovrebbe essere sempre al sicuro, ma secondo me il metodo dovrebbe puntare sempre a $ apply (). L’attuale app Angolare su cui sto lavorando è abbastanza grande e abbiamo dovuto fare affidamento solo su $ timeout una volta invece di $ apply ().

Se usiamo $ si applicano pesantemente nell’applicazione, potremmo ottenere l’errore: $ digest già in corso. Succede perché un ciclo di digest $ può essere eseguito alla volta. Possiamo risolverlo con $ timeout o $ evalAsync.

Il timeout $ non genera errori come “$ digest già in corso” perché $ timeout dice ad Angular che dopo il ciclo corrente, c’è un timeout in attesa e in questo modo garantisce che non ci saranno collisioni tra i cicli digest e quindi l’output di $ il timeout verrà eseguito in un nuovo ciclo $ digest.

Ho provato a spiegarli a: Confronto di applicare, timeout, digest ed evalAsync .

Forse ti aiuterà.

Per quanto ho capito, $timeout è un wrapper attorno a setTimeout che chiama implicitamente $scope.$apply , vale a dire che gira al di fuori del ciclo di vita angular, ma avvia il ciclo di vita angular stesso. L’unico “raggiro” che posso pensare è che se ti aspetti che i tuoi risultati siano disponibili in questo $digest , devi trovare un altro modo per applicare “sicuro” (che, AFAIK, è disponibile solo tramite $scope.$$phase ).