¿Cuál es la diferencia entre $ evalAsync y $ timeout en AngularJS?

180

He estado usando AngularJS durante un tiempo, y he encontrado la necesidad de usar $ timeout de vez en cuando (parece ser que generalmente se inicia un complemento jQuery).

Recientemente, he estado tratando de obtener una comprensión mejor y más profunda del ciclo de resumen, y me encontré con la función $ evalAsync .

Parece que esa función produce resultados similares a $timeout, solo que no le das retraso. Cada vez que lo he usado $timeoutha sido con un retraso de 0, así que ahora me pregunto si debería haberlo usado $evalAsync.

¿Hay alguna diferencia fundamental entre los dos? ¿Qué casos usarías uno sobre el otro? Me gustaría tener una mejor idea de cuándo usar cuál.

dnc253
fuente

Respuestas:

263

Recientemente respondí esencialmente esta pregunta aquí: https://stackoverflow.com/a/17239084/215945 (Esa respuesta se vincula a algunos intercambios de github con Misko).

Para resumir:

  • si el código se pone en cola usando $ evalAsync desde una directiva , debe ejecutarse después de que Angular haya manipulado el DOM, pero antes de que el navegador muestre
  • si el código se pone en cola usando $ evalAsync desde un controlador , debe ejecutarse antes de que Angular haya manipulado el DOM (y antes de que se muestre el navegador); rara vez quiere esto
  • si el código se pone en cola usando $ timeout , debe ejecutarse después de que Angular haya manipulado el DOM y después de que el navegador se procese (lo que puede causar parpadeo en algunos casos)
Mark Rajcok
fuente
15
Gracias por la explicación. Sin embargo, hay una cosa que no estoy seguro de entender. ¿Por qué hace una diferencia si llamas a $ evalAsync desde un controlador o una directiva? El asyncQueue no sabe si se registró desde un controlador o una directiva, solo lo pone en cola en el alcance actual. ¿Tiene que ver con cuando las cosas se ejecutan en un controlador frente a un controlador? Solo quiero entender esa parte.
dnc253
@ dnc253, no he mirado el código angular, así que no sé la respuesta a su (buena) pregunta. Esperemos que alguien más pueda comentar.
Mark Rajcok
15
Qué significa "de una directiva" significa "de la función de enlace de una directiva"? ¿O eso es cierto del comportamiento cuando se ejecuta desde el método de enlace o controlador de una directiva?
SimplGy
55
sí, no está muy claro qué significan "de una directiva" y "de un controlador" aquí
thorn̈
1
@MarkRajcok, ¿puede aclarar aquí: si el código se pone en cola usando $ evalAsync desde una directiva, debe ejecutarse después de que el DOM haya sido manipulado por Angular , ¿debería ejecutarse después de que el DOM haya sido manipulado por esta directiva o por otras directivas?
Max Koretskyi
59

Para aquellos que crean aplicaciones complejas, tenga en cuenta que hay un impacto en el rendimiento de su elección. Además, me gustaría completar la respuesta de Mark con más detalles técnicos:

  • $ timeout (devolución de llamada) esperará a que se realice el ciclo de resumen actual (es decir, actualización angular de todos los modelos y DOM), luego ejecutará su devolución de llamada, que posiblemente afecte al modelo angular, y luego lanzará un completo $applyen la raíz $ alcance y redirigirá todo.

  • $ evalAsync (devolución de llamada) , por otro lado, agregará la devolución de llamada al ciclo de resumen actual o siguiente. Lo que significa que si está dentro de un ciclo de resumen (por ejemplo, en una función llamada desde alguna ng-clickdirectiva), esto no esperará nada, el código se ejecutará de inmediato. Si está dentro de una llamada asincrónica, por ejemplo a setTimeout, $applyse activará un nuevo ciclo de resumen ( ).

Entonces, en términos de rendimiento, siempre es mejor llamar $evalAsync, a menos que sea importante para usted que la vista esté actualizada antes de ejecutar su código, por ejemplo, si necesita acceder a algún atributo DOm, como el ancho de los elementos y similares.

Si desea más detalles sobre la distinción entre $ timeout, $ evalAsync, $ digest, $ apply, lo invito a leer mi respuesta sobre esa otra pregunta: https://stackoverflow.com/a/23102223/1501926

También asegúrese de leer la documentación :

$ EvalAsync no garantiza cuándo se ejecutará la expresión, solo que:

  • se ejecutará después de la función que programó la evaluación (preferiblemente antes de la representación DOM).
  • se realizará al menos un ciclo de $ digest después de la ejecución de la expresión.

Nota: si esta función se llama fuera de un ciclo $ digest, se programará un nuevo ciclo $ digest . Sin embargo, se recomienda llamar siempre al código que cambia el modelo desde una llamada $ apply. Eso incluye el código evaluado a través de $ evalAsync.

floribon
fuente
¿Puede explicar por qué se necesita $ timeout si necesito acceder a algún atributo DOM? Digamos que si tengo <table width = "{{x}}"> La función watch de ng-bind no actualiza el atributo dom en la memoria, entiendo que no tendrá la oportunidad de volver a pintar la vista hasta que finalice el ciclo de resumen.
Sridhar Chidurala
2
@SridharChidurala debido a que el DOM (el "HTML") se actualiza durante el ciclo de resumen, debe esperar a que se realice antes de poder leer las mofificaciones. Sin embargo, Angular lo desaconseja, debe leer xdesde su alcance directamente en lugar de desde el DOM, por lo que no tiene que esperar nada. Además, debería usarlo mejor ng-stylecon CSS en lugar de la widthpropiedad obsoleta . Si necesita más ayuda, abra una nueva pregunta en StackOverflow.
floribon