Solución:
NgZone
es un contenedor de Zone.js, que es una biblioteca que crea un contexto en torno a funciones asincrónicas para hacerlas rastreables.
La detección de cambios de Angular depende en gran medida de Zones
, ¿Cómo?
Angular necesita una forma de entender cuándo es el momento de ejecutar la detección de cambios, que básicamente no es más que actualizar el DOM
para representar los últimos cambios del modelo (javascript).
Imagina que tenemos el siguiente ejemplo:
<div id="content"></div>
Y en algún lugar de nuestro código javascript, tenemos
const element = document.getElementById('content');
function updateText(){
element.innerHtml = myText+ ": updated at time"+Date.now()
}
Digamos que inicialmente voy a actualizar el content
con un hola:
const myText = "Hello";
this.updateText();
Esto actualizará mi contenido HTML al texto: “Hola actualizado a las 19:30”
y luego digamos que quiero actualizar el myText
variable para ser otra cosa después de que un usuario haga clic:
<button onClick="updateTheTextAgain()"></button>
updateTheTextAgain(){
this.myText = "Hi there";
}
¿Qué pasará si hago clic en ese botón?
Nada;
Bueno, en realidad, no es “nada”, logré actualizar la variable, pero NO actualicé la vista (no detecté los cambios del modelo), así que necesito ajustar mi updateTheTextAgain
ser :
updateTheTextAgain(){
this.myText = "Hi there";
this.updateText(); /// Making sure I'm detecting the change ( I'm updating the `DOM`)
}
Ahora, al hacer clic en el botón se actualizará mi vista (debido a la detección manual de cambios).
Obviamente, esta no es la mejor idea, porque luego tengo que escribir mucho updateText
funciones y llamarlas en cualquier lugar donde quiera que se actualice la vista después de actualizar el modelo, a la derecha (Vuelva a Angular1 y recuerde $scope.apply()
)?
Aquí es donde ZoneJs
es asombroso.
Imagínese si pudiera reescribir el onClick
función, me refiero a que la función onClick original del navegador sea:
const originalOnClick = window.onClick;
window.onClick = function(){
originalOnClick();
this. updateText();
}
Se llama monkey patching
o open heart surgery
de funciones nativas.
¿Qué obtengo con esto?
Después de poner mi patched onClick
en la página, todos los onClick
función que se escribirá en toda la aplicación, pasará por mi patched onClick
, lo que significa que no tengo que correr updateText()
ya funciona después de cada clic, porque está integrado en el click
controlador de eventos en sí.
En Angular, eso updateText
es el change detection
, Angular tiene ganchos en todos los eventos nativos (mediante el uso de Zonas).
Entonces, cuando escribes:
setTimeout(()=>{
console.log('Do something');
},100);
Lo que en realidad estás escribiendo es algo como:
setTimeout(()=>{
console.log('Do something');
runAngularsChangeDetection();
},100);
Lo anterior está muy lejos de lo que está sucediendo en la realidad, pero es el corazón de toda la historia de la detección de cambios y Zones
Y por qué los necesitamos/
** ACTUALIZAR:**
Cuando debemos usar NgZone
.
Habría muchos casos en los que quisiera usar NgZone
, Puedo nombrar dos:
1- Cuando desee que algo se ejecute fuera de la detección de cambios de Angular:
¿Recuerdas que dije que Angular tiene ganchos en todos los eventos asíncronos? window.onScroll
es uno de ellos, ahora digamos que queremos hacer algún cálculo cuando el usuario se desplaza, lo que normalmente haces es:
window.onscroll = ()=>{
// do some heavy calculation :
}
Ahora, cuando se desplaza, su función se llama normalmente como es de esperar, pero es posible que note que tiene un pequeño problema de rendimiento y eso podría deberse a que Angular está ejecutando el changeDetection
en cada evento de desplazamiento (comportamiento esperado).
Si tiene muchos enlaces en su componente, definitivamente notará que el rendimiento se reduce en el pergamino.
Así que una forma es decir, oye Angular, ignora mi onscroll
evento, sé lo que estoy haciendo, no quiero que ejecutes la detección de cambios, en este caso, usarías NgZone
constructor(private zone:NgZone){
this.zone.runOutsideOfAngular(()=>{
window.onscroll = ()=>{
// do some heavy calculation :
}
})
}
Esto asegurará que Angular no ejecutará la detección de cambios al desplazarse.
Otro caso sería exactamente lo opuesto al anterior, donde tiene una función que de alguna manera está fuera de la zona de Angular y desea que esté adentro, como cuando una biblioteca de terceros está haciendo algunas cosas por usted y desea que esté vinculada a su ciclo angular.
this.zone.run(()=>{
$.get('someUrl').then(()=>{
this.myViewVariable = "updated";
})
});
Sin usar Zone, lo más probable es que deba hacer lo siguiente:
$.get('someUrl').then(()=>{
this.myViewVariable = "updated";
this.changeDetectorRef.detectChanges();
})
Pero tenga en cuenta que cuando su función está dentro de la zona (el método de ejecución) no tiene que llamar al detectChanges
manualmente usted mismo y angular harán el trabajo
El documento oficial actual no está a la altura. Hay gente que hace locuras en Angular y también lo hace Pascal Precht. Su artículo a continuación te ayudará a comprender qué es Zone
y ngZone
.
https://blog.ilsttram.io/angular/2016/02/01/zones-in-angular-2.html