javascript angularjs rootscope

javascript - ¿Por qué no se recomienda usar $ rootScope con funciones?



angularjs (3)

Mientras estoy mirando las FEQ de Angularjs, he visto el siguiente artículo:

$ rootScope existe, pero se puede usar para el mal

Los ámbitos en Angular forman una jerarquía, que se hereda prototípicamente de un ámbito raíz en la parte superior del árbol. Por lo general, esto puede ignorarse, ya que la mayoría de las vistas tienen un controlador y, por lo tanto, un alcance propio.

Ocasionalmente, hay datos que desea que sean globales para toda la aplicación. Para estos, puede inyectar $rootScope y establecer valores en él como cualquier otro ámbito. Dado que los ámbitos heredan del ámbito raíz, estos valores estarán disponibles para las expresiones adjuntas a directivas como ng-show al igual que los valores en su $scope local.

Por supuesto, el estado global apesta y debe usar $rootScope moderación, como lo haría (con suerte) con variables globales en cualquier idioma. En particular, no lo use para código, solo datos. Si tiene la tentación de poner una función en $rootScope , casi siempre es mejor ponerla en un servicio que pueda inyectarse donde sea necesario y probarse más fácilmente.

Por el contrario, no cree un servicio cuyo único propósito en la vida sea almacenar y devolver bits de datos.

- Preguntas frecuentes sobre AngularJS - $ rootScope existe, pero se puede usar para el mal

Entonces, mi duda es por qué $ rootScope no se recomienda para funciones como una función global. ¿Hay algún problema de rendimiento?


Las variables globales son abusadas

$rootScope es más o menos una variable global y tiene su lugar, pero definitivamente es abusado por la mayoría de las personas que lo usan. Estas son las razones por las que Globals en general no debe usarse.

No localidad : el código fuente es más fácil de entender cuando el alcance de sus elementos individuales es limitado. Las variables globales pueden ser leídas o modificadas por cualquier parte del programa, lo que hace difícil recordar o razonar sobre cada posible uso.

Sin control de acceso o verificación de restricciones : cualquier parte del programa puede obtener o establecer una variable global, y cualquier regla con respecto a su uso se puede romper u olvidar fácilmente. (En otras palabras, los accesos get / set son generalmente preferibles al acceso directo a datos, y esto es aún más importante para los datos globales). Por extensión, la falta de control de acceso dificulta en gran medida el logro de la seguridad en situaciones en las que es posible que desee ejecutar código no confiable (como trabajar con complementos de terceros).

Acoplamiento implícito : un programa con muchas variables globales a menudo tiene acoplamientos estrechos entre algunas de esas variables y acoplamientos entre variables y funciones. Agrupar elementos acoplados en unidades cohesivas generalmente conduce a mejores programas.

Problemas de concurrencia : si múltiples hilos de ejecución pueden acceder a los globales, la sincronización es necesaria (y con demasiada frecuencia se descuida). Al vincular dinámicamente módulos con globales, el sistema compuesto podría no ser seguro para subprocesos incluso si los dos módulos independientes probados en docenas de contextos diferentes estuvieran seguros.

Contaminación del espacio de nombres : los nombres globales están disponibles en todas partes. Sin saberlo, puede terminar usando un global cuando cree que está usando un local (al escribir mal u olvidarse de declarar el local) o viceversa. Además, si alguna vez tiene que vincular módulos que tienen los mismos nombres de variables globales, si tiene suerte, obtendrá errores de vinculación. Si no tiene suerte, el enlazador simplemente tratará todos los usos del mismo nombre como el mismo objeto.

Problemas de asignación de memoria : algunos entornos tienen esquemas de asignación de memoria que dificultan la asignación de globales. Esto es especialmente cierto en los lenguajes donde los "constructores" tienen efectos secundarios distintos de la asignación (porque, en ese caso, puede expresar situaciones inseguras en las que dos globales dependen mutuamente). Además, cuando se vinculan módulos dinámicamente, no está claro si las diferentes bibliotecas tienen sus propias instancias de globales o si las globales son compartidas.

Pruebas y confinamiento : la fuente que utiliza globales es algo más difícil de probar porque no se puede configurar fácilmente un entorno "limpio" entre las ejecuciones. En términos más generales, la fuente que utiliza servicios globales de cualquier tipo (por ejemplo, leer y escribir archivos o bases de datos) que no se proporcionan explícitamente a esa fuente es difícil de probar por la misma razón. Para los sistemas de comunicación, la capacidad de probar invariantes del sistema puede requerir ejecutar más de una ''copia'' de un sistema simultáneamente, lo que se ve obstaculizado en gran medida por el uso de servicios compartidos, incluida la memoria global, que no se proporcionan para compartir como parte de la prueba .

Fuente : http://c2.com/cgi/wiki?GlobalVariablesAreBad

Compartir datos en angular

Cuando se trata de compartir datos entre controladores en Angular, debe usar un servicio. Con su servicio personalizado puede crear un método getter y setter. Lo inyecta en los controladores que lo necesita y puede usarlo en su aplicación.


He respondido esto en el pasado, pero es bueno que hagas estas preguntas.

$ rootScope existe, pero se puede usar para ámbitos malvados en forma angular, una jerarquía, que se hereda prototípicamente de un ámbito raíz en la parte superior del árbol. Por lo general, esto puede ignorarse, ya que la mayoría de las vistas tienen un controlador y, por lo tanto, un alcance propio.

Los ámbitos no aislados son jerárquicos, pero la mayoría de los desarrolladores deberían utilizar directivas que tengan ámbitos aislados. La naturaleza muy jerárquica del alcance de AngularJS es la fuente de muchos errores en las aplicaciones angulares. Es un problema que me gusta llamar sangrado de alcance donde una propiedad de alcance se modifica mágicamente en algún lugar del árbol DOM y no sabes por qué.

El comportamiento predeterminado de Angular es los ámbitos inherentes y esto hace que sea tentador para un controlador actualizar algo administrado por otro controlador, y así sucesivamente. Así es como se crean las conexiones de espagueti entre el código fuente. Haciendo que sea muy difícil mantener ese código.

Ocasionalmente, hay datos que desea que sean globales para toda la aplicación. Para estos, puede inyectar $ rootScope y establecer valores en él como cualquier otro ámbito.

No, eso no es correcto. AngularJS le permite definir cosas como constantes, valores y servicios. Estas son cosas que pueden inyectarse en rutas, controladores y directivas. Así es como hace que las cosas sean accesibles globalmente para su aplicación, y así es como lo hace si desea que sus controladores o directivas sean verificables. Un escritor de pruebas unitarias no sabe qué propiedades deberían estar en $ rootScope de las que depende una directiva o controlador. Deben suponer que $ rootScope no ha mutado para proporcionar un servicio o datos.

Por supuesto, el estado global apesta y debe usar $ rootScope con moderación, como lo haría (con suerte) con variables globales en cualquier idioma.

El problema no es $ rootScope sino lo que la gente está haciendo con él. Muchas aplicaciones agregan el usuario actual, los tokens de autenticación y los datos de la sesión en rootScope. Esto termina siendo utilizado en gran medida en las plantillas (muestra X si el usuario inició sesión, de lo contrario, muestra Y). El problema es que el HTML no comunica la jerarquía de alcance. Entonces, cuando ve {{user.firstname + '' '' + user.lastname}} no tiene idea de dónde vino la variable user . El segundo problema es que los ámbitos secundarios pueden sombrear las propiedades de la raíz. Como en el ejemplo anterior, si una directiva hace esto scope.user = ''bla bla bla'' . No ha reemplazado el valor en rootScope. Está escondido Ahora obtienes algunas cosas extrañas e inesperadas en las plantillas, y no sabes por qué la variable user ha cambiado.

Por el contrario, no cree un servicio cuyo único propósito en la vida sea almacenar y devolver bits de datos.

$cacheFactory y $templateCache Angular son ejemplos de servicios que solo existen para almacenar datos. Creo que el autor estaba tratando de alentar el uso de constantes y valores en los módulos de Angular, pero esa no es una buena descripción para hacerlo.

Entonces, mi duda es por qué $ rootScope no se recomienda para funciones como una función global. ¿Hay algún problema de rendimiento?

$ RootScope es el único alcance disponible durante angular.config(..) . Es durante este tiempo que se puede modificar el alcance si esta es la única vez que puede hacerlo. Por ejemplo; Es posible que deba inyectar una clave API o una variable de análisis de Google antes de que se inicie la aplicación.

Las funciones en cualquier ámbito son generalmente una mala idea. Principalmente por la razón de que todo en los ámbitos se digiere en expresiones en las plantillas. Funciones de carpa para ocultar operaciones pesadas. Es imposible saber qué tan pesada es una plantilla leyendo el HTML cuando llama a una función. He visto funciones de alcance como getHeight() donde la función misma realizó 3 niveles de bucles anidados. Esa función debe llamarse cada vez que angular digiere a los observadores para ver si ha cambiado. Debes tratar de mantener tus plantillas lo más secas posible.


No existen problemas de rendimiento. Realmente aumentaría su rendimiento por una fracción de tiempo , porque no necesita inyectar muchos servicios por dependencia.

Pero es una gran preocupación del diseño. Considere una aplicación grande con docenas y docenas de vistas, componentes complejos y vinculados a una serie de API bien conocidas (por ejemplo, Twitter, Flickr, Facebook, OAuth, ...).

No desarrollarás esta aplicación solo. Surgirán los siguientes problemas:

Espacio de nombres

Estás trabajando en la API de Facebook, alguien más está trabajando en la API de Twitter. Ambos piensan que usar $rootScope para funciones es una buena idea y ambos escriben una función $rootScope.login . ¿Cómo resolverías esto al hacer git merge ? Necesita espacios de nombres, por desgracia, necesita desarrollar dos servicios myFacebookAPI , myTwitterAPI que luego pueden implementar la misma interfaz para login(user,pw) ). Tenga en cuenta que esto le brinda la capacidad de abstraer la red social real con la que está tratando en el controlador, cuando puede hacer algo como:

$scope.callAction = function (action) { var service; if ($scope.serviceSelected === ''fb'') { service = myFacebookAPI; } else { service = myTwitterAPI; } service[action](); };

Pruebas

Cuando se desarrolla profesionalmente, escribe pruebas. Angular le brinda herramientas para realizar pruebas automatizadas de servicios, etc., pero no podrá probar algo que asigne a $rootScope de la misma manera cómoda.

También surgirán otros problemas, pero creo que esto debería ser suficiente para que lo pienses por tu cuenta.