Qual è la differenza tra $ evalAsync e $ timeout in AngularJS?


180

Sto usando AngularJS da un po 'di tempo, e ho trovato la necessità di usare $ timeout ogni tanto (sembra essere di solito per avviare un plugin jQuery).

Di recente, ho cercato di ottenere una migliore e più approfondita comprensione del ciclo digest e ho scoperto la funzione $ evalAsync .

Sembra che quella funzione produca risultati simili a $timeout, solo tu non gli dai ritardo. Ogni volta che l'ho usato $timeoutè stato con un ritardo di 0, quindi ora mi chiedo se avrei dovuto usare $evalAsyncinvece.

Ci sono differenze fondamentali tra i due? Quali casi useresti l'uno rispetto all'altro? Mi piacerebbe avere un'idea migliore di quando usare quale.

Risposte:


263

Di recente ho risposto essenzialmente a questa domanda qui: https://stackoverflow.com/a/17239084/215945 (Questa risposta si collega ad alcuni scambi di github con Misko.)

Riassumere:

  • se il codice è messo in coda usando $ evalAsync da una direttiva , dovrebbe essere eseguito dopo che il DOM è stato manipolato da Angular, ma prima che il rendering del browser
  • se il codice viene messo in coda usando $ evalAsync da un controller , dovrebbe essere eseguito prima che il DOM sia stato manipolato da Angular (e prima che il rendering del browser) - raramente lo vuoi
  • se il codice viene messo in coda utilizzando $ timeout , dovrebbe essere eseguito dopo che DOM è stato manipolato da Angular e dopo il rendering del browser (che in alcuni casi può causare sfarfallio)

15
Grazie per la spiegazione. Una cosa non sono sicuro di aver capito però. Perché fa la differenza se chiami $ evalAsync da un controller o da una direttiva? AsyncQueue non sa se è stato registrato da un controller o da una direttiva, ma lo mette in coda solo nell'ambito corrente. Ha a che fare con le cose che funzionano in un controller contro un controller? Voglio solo capire quella parte.
dnc253,

@ dnc253, non ho esaminato il codice angolare, quindi non conosco la risposta alla tua (buona) domanda. Spero che qualcun altro possa commentare.
Mark Rajcok,

15
"da una direttiva" significa "dalla funzione di collegamento di una direttiva"? O è vero per il comportamento quando eseguito dal metodo link o controller di una direttiva?
Semplicemente dal

5
sì, non è davvero chiaro cosa significhino qui "da una direttiva" e "da un controllore"
thorn̈

1
@MarkRajcok, puoi chiarire qui: se il codice è messo in coda usando $ evalAsync da una direttiva, dovrebbe essere eseguito dopo che il DOM è stato manipolato da Angular - dovrebbe funzionare dopo che il DOM è stato manipolato da questa direttiva o da altre direttive?
Max Koretskyi,

59

Per coloro che creano applicazioni complesse, tenere presente che le prestazioni possono essere influenzate dalle prestazioni. Inoltre, vorrei completare la risposta Mark con ulteriori dettagli tecnici:

  • $ timeout (callback) attenderà il completamento del ciclo digest attuale (ovvero l'aggiornamento angolare di tutti i modelli e il DOM), quindi eseguirà il suo callback - potenzialmente influenzando il modello angolare - quindi avvierà un full $applysull'ambito $ root e ridigesterà qualunque cosa.

  • $ evalAsync (callback) , d'altra parte, aggiungerà il callback al ciclo digest attuale o successivo. Ciò significa che se ci si trova all'interno di un ciclo digest (ad esempio in una funzione chiamata da qualche ng-clickdirettiva), questo non attenderà nulla, il codice verrà eseguito immediatamente. Se ci si trova in una chiamata asincrona, ad esempio a setTimeout, $applyverrà attivato un nuovo ciclo digest ( ).

Quindi in termini di prestazioni è sempre meglio chiamare $evalAsync, a meno che non sia importante per te che la vista sia aggiornata prima di eseguire il tuo codice, ad esempio se hai bisogno di accedere ad alcuni attributi DOm come larghezza degli elementi e simili.

Se vuoi maggiori dettagli sulla distinzione tra $ timeout, $ evalAsync, $ digest, $ apply, ti invito a leggere la mia risposta su quell'altra domanda: https://stackoverflow.com/a/23102223/1501926

Assicurati anche di leggere la documentazione :

$ EvalAsync non fornisce garanzie su quando verrà eseguita l'espressione, solo che:

  • verrà eseguito dopo la funzione che ha pianificato la valutazione (preferibilmente prima del rendering DOM).
  • almeno un ciclo $ digest verrà eseguito dopo l'esecuzione dell'espressione.

Nota: se questa funzione viene chiamata al di fuori di un ciclo $ digest, verrà pianificato un nuovo ciclo $ digest . Tuttavia, si consiglia di chiamare sempre il codice che modifica il modello dall'interno di una chiamata $ apply. Ciò include il codice valutato tramite $ evalAsync.


Puoi spiegare perché $ timeout è necessario se devo accedere ad alcuni attributi DOM. Diciamo che se ho <table width = "{{x}}"> La funzione watch di ng-bind non aggiorna l'attributo dom in memoria, capisco che non avrà la possibilità di ridipingere la vista fino a quando il ciclo digest non termina.
Sridhar Chidurala,

2
@SridharChidurala perché il DOM (l '"HTML") viene aggiornato durante il ciclo digest, devi aspettare che sia fatto prima di poter leggere le mofificazioni. Tuttavia, questo è scoraggiato da Angular, dovresti leggere xdirettamente dal tuo ambito piuttosto che dal DOM, quindi non devi aspettare nulla. Inoltre, dovresti usare meglio ng-stylecon CSS piuttosto che la widthproprietà obsoleta . Se hai bisogno di ulteriore aiuto, ti preghiamo di aprire una nuova domanda su StackOverflow.
floribon,
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.