Reputation: 1536
I need to have a setInterval in one of my child components to check one of my DIV height. Problem is I found out that this setInterval cause my component UI non-stop update itself. Event the parent component also non-stop update itself.
@Component({
selector: 'app-test-comp',
template: `
<ul>
<li *ngFor="let num of [1,2,3]">
{{ print(num) }}
</li>
</ul>
`,
})
class TestComponent {
private attr: Date;
constructor() {
setInterval(() => {}, 1000)
}
print(num) {
return num + ' ' + new Date();
}
}
@Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<ul>
<li *ngFor="let num of [1,2,3,4]">{{ test(num) }}</li>
</ul>
<app-test-comp></app-test-comp>
</div>
`,
})
export class App {
name:string;
constructor() {
this.name = `Angular! v${VERSION.full}`
}
test(num) {
return num + ' ' + new Date()
}
}
Refer to plunker link above, it clearly shows that root component and its child component keep on updating its UI. If I remove that setInterval in app.ts line 18, it will behave as normal.
I wish to know what causes the non-stop update UI problem and how to prevent that.
Upvotes: 0
Views: 1916
Reputation: 4335
The async methods like setInterval
are monkey patched by zone.js
, a library used by angular to
update the view after model has changed. Monkey patching means extending functionality of a method.
So whenever the setInterval
is called, the angular change detection is fired to update the view.
You can run your code outside of angular to avoid running change detection:
constructor(
private zone: NgZone
) {
this.zone.runOutsideAngular(() => {
setInterval(() => {}, 1000)
})
}
I have updated your plnkr with above example
Upvotes: 1
Reputation: 14257
Angular depends on zone.js
and zone monkey patches native methods like setTimeout
and setInterval
, therefore if you're using setInterval
you're actually using the patched version, therefore angular is updating the UI.
To prevent this angular has a service called NgZone which implements a way to run methods outside the angular zone.
For example:
import { NgZone } from '@angular/core';
constructor(private _zone: NgZone) {
this._zone.runOutsideAngular(() => {
setInterval(() => {}, 1000); // this runs outside of the angular zone
this._zone.run(() => {
// this runs inside the angular zone
});
});
}
A more detailed explanation about zones in angular can be found in this article.
Upvotes: 2