Simon
Simon

Reputation: 1536

Angular, setInterval cause component to non-stop update its UI

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()
  }
}

PlunkerLink

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

Answers (2)

Dhyey
Dhyey

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

cyr_x
cyr_x

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

Related Questions