$ apply vs $ digest en pruebas de directivas

98

Si tengo una directiva que responde al estado de un atributo en particular en el alcance, y quiero cambiar ese atributo en mi prueba y verificar que responde correctamente, ¿cuál es la mejor manera de hacer ese cambio?

He visto estos dos patrones:

scope.$apply(function() {
    scope.myAttribute = true;
});

y

scope.myAttribute = true;
scope.$digest();

¿Cuál es la diferencia entre ellos, cuál es mejor y por qué?

Daniel Roseman
fuente

Respuestas:

206

scope.$digest()disparará a los observadores sobre el alcance actual, y también sobre todos sus hijos. scope.$applyevaluará la función pasada y la ejecutará $rootScope.$digest().

El primero es más rápido, ya que necesita evaluar a los observadores para el alcance actual y sus hijos. El segundo es más lento, ya que necesita evaluar a los observadores $rootScopey todos sus ámbitos secundarios.

Cuando ocurre un error en uno de los observadores y lo usa scope.$digest, no se maneja a través del $exceptionHandlerservicio, por lo que debe manejar la excepción usted mismo. scope.$applyutiliza un try-catchbloque internamente y pasa todas las excepciones a $exceptionHandler.

Tadeusz Wójcik
fuente
1
¿ $digestTambién se llamará a los hijos del osciloscopio?
Pilau
15
Esto puede resultar engañoso. $digestno solo dispara a los observadores en el alcance actual, sino también a todos sus hijos.
tasseKATT
@tasseKATT, creo que he captado lo que sugiere tu comentario.
activedecay
12

Como la documentación misma menciona, el ciclo de $ digest se realiza cada vez que lo hace $scope.$apply. Según la guía del desarrollador sobre el alcance

Después de evaluar la expresión, el método $ apply realiza un $ digest. En la fase $ digest, el ámbito examina todas las expresiones $ watch y las compara con el valor anterior.

Y según la documentación de la API de alcance

Por lo general, no llama a $ digest () directamente en controladores o directivas. En cambio, una llamada a $ apply () (normalmente desde dentro de directivas) forzará un $ digest ().

Por lo tanto, no debe llamar explícitamente $digest, su $applymétodo de llamada desencadenaría un ciclo de resumen.

Chandermani
fuente
8
esto no es cierto ya que el resumen es suficiente para la mayoría de los casos en los que solo es necesario evaluar el alcance actual y sus elementos secundarios. es cierto que $ scope. $ aplica llamadas $ digest internamente, pero es muy importante recordar que terminará llamando a $ rootScope. $ digest () y, por lo tanto, muy pesado
Srivathsa Harish Venkataramana