2014-04-14 23 views
62

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 angolare oa un evento non angolare come jQuery o qualche evento DOM standard.

mi pare di capire le cose:. Codice

  1. Wrapping a $ portata $ applicare funziona bene per scenari in cui si non sono già in un ciclo digerire (aka eventi jQuery.), Ma genererà un errore se un digest è in corso
  2. codice
  3. Wrapping in un $ timeout() con nessun parametro di ritardo funziona se già in un ciclo digest o no

Guardando il codice sorgente angolare, sembra $ timeout effettua una chiamata a $ rootScope. $ apply().

  1. Perché il timeout di $() non genera un errore se è già in corso un ciclo di digest?
  2. È consigliabile utilizzare $ scope. $ Apply() quando si è sicuri che un digest non sarà già in corso e $ timeout() quando è necessario che sia sicuro in entrambi i casi?
  3. $ timeout() è davvero accettabile come "applicazione sicura" o ci sono trucchi?

Grazie per qualsiasi intuizione.

risposta

53

Looking at Angular source code, it looks like $timeout makes a call to $rootScope.$apply().

  • Why doesn't $timeout() also raise an error if a digest cycle is already in progress?

$timeout si avvale di un servizio di angolare non documentato $browser. In particolare, utilizza $browser.defer() che rimuove l'esecuzione della funzione in modo asincrono tramite , che verrà sempre eseguito al di fuori del ciclo di vita angolare. Solo una volta window.setTimeout ha sparato la tua funzione sarà $timeout chiamata $rootScope.$apply().

  • Is the best practice to use $scope.$apply() when you know for sure that a digest won't already be in progress and $timeout() when needing it to be safe either way?

Direi di sì. 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 di $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.

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

+0

Nel mio progetto, ho uno scenario in cui Ho bisogno di aumentare $ scope. $ digest() per catturare gli eventi accaduti fuori dalla vista di Angular. È scaduto il n orm per safeApply o safeDigest o questo è stato risolto in modo intelligente all'interno del framework? – TrueBlue

+1

Perché hai dovuto fare affidamento su '$ timeout' invece di' $ apply'? Se non puoi condividere il codice, potresti almeno discutere la ragione di base? – trysis

4

Per quanto ho capito, $timeout è un wrapper setTimeout che richiede implicitamente $scope.$apply, il che significa che corre fuori del ciclo di vita angolare, ma kickstart il ciclo di vita angolare stesso. L'unico "raggiro" che posso pensare è che se ti aspetti che il tuo risultato sia disponibile questo$digest, devi trovare un altro modo per "applicare sicuro" (che, AFAIK, è disponibile solo tramite $scope.$$phase).

13

Se usiamo $ applicare 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 un errore come "$ digest già in corso" perché $ timeout indica 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 di digest e in tal modo l'uscita di $ timeout eseguirà su un nuovo ciclo di $ digerire

ho cercato di spiegare loro a:... Comparison of apply, timeout,digest and evalAsync

Può essere che vi aiuterà a

+0

Sei corretto e il tuo input ha preso in considerazione. –

+0

Grazie Rahul, l'articolo è interessante. Ciò che sentivo che mancava era una raccomandazione su quale usare, o su quale usare quando. Grazie ancora. –

+1

Grazie Matty per l'input. A mio parere, $ evalAsync è l'opzione migliore rispetto a quella disponibile. –

Problemi correlati