Как я могу использовать функцию Rx js для интервала без выполнения процедуры обнаружения изменений? - PullRequest
0 голосов
/ 03 марта 2020

Я хочу показать время работы сервера в приложении. Затем я создал компонент, который использует функцию RX JS «интервал» для обновления времени каждую секунду, но он выполняет процедуру обнаружения изменений каждую секунду!

Как я могу обновить время, не вызывая обнаружение изменений?

Это мой компонент:

server-time.component.ts:

export class ServerTimeComponent implements OnInit {
  serverTime: Date;
  serverDatetime: InfoDatetime;

  constructor(private infoService: InfoService) {}

  ngOnInit() {
    this.getServerDate();

    // Increase time by interval
    interval(1000).subscribe(() => {
      // Skip if the time is not ready
      if (this.serverTime === undefined) {
        return;
      }

      // Update the time
      this.serverTime = new Date(this.serverTime.getTime() + 1000);
      // If it's midnight, get the date again
      if (
        this.serverTime.getHours() === 0 &&
        this.serverTime.getMinutes() === 0 &&
        this.serverTime.getSeconds() < 2
      ) {
        this.getServerDate();
      }
    });
  }

  getServerDate() {
    this.infoService
      .getServerDatetime()
      .subscribe((res: ApiResponse<InfoDatetime>) => {
        if (res.code === 1) {
          this.serverDatetime = res.data;

          // Create a new Date. Time part will be used
          this.serverTime = new Date('2000-01-01 ' + this.serverDatetime.time);
        }
      });
  }
}

server-time.component. html:

<span *ngIf="serverDatetime">
  <span class="ml-1">{{serverTime | date:'hh:mm:ss'}}</span>
  —
  <span class="mr-1">{{serverDatetime?.date_jalali}}</span>
</span>

И это воспроизводимая проблема в stackblitz.io:

https://angular-ibcvbp.stackblitz.io

Спасибо

Ответы [ 3 ]

1 голос
/ 03 марта 2020

Вам нужно использовать метод NgZone runOutside Angular

export class ServerTimeComponent implements OnInit {
  serverTime: Date;
  serverDatetime: InfoDatetime;

  constructor(private infoService: InfoService, public zone: NgZone) {}

  ngOnInit() {
    this.getServerDate();

    // Increase time by interval

    this.ngZone.runOutsideAngular( ()=> {
        interval(1000).subscribe(() => {
      // Skip if the time is not ready
      if (this.serverTime === undefined) {
        return;
      }

      // Update the time
      this.serverTime = new Date(this.serverTime.getTime() + 1000);
      // If it's midnight, get the date again
      if (
        this.serverTime.getHours() === 0 &&
        this.serverTime.getMinutes() === 0 &&
        this.serverTime.getSeconds() < 2
      ) {
        this.getServerDate();
      }
    });

    });

  }

  getServerDate() {
    this.infoService
      .getServerDatetime()
      .subscribe((res: ApiResponse<InfoDatetime>) => {
        if (res.code === 1) {
          this.serverDatetime = res.data;

          // Create a new Date. Time part will be used
          this.serverTime = new Date('2000-01-01 ' + this.serverDatetime.time);
        }
      });
  }
}
0 голосов
/ 03 марта 2020

Вам не хватает того, что вы не удалили предыдущий интервал или не отменили его. Нравится:

if(this.interval !== undefined) { 
  clearInterval(this.interval); //this.interval.unsubscribe();
}
this.interval =  interval(1000).subscribe(() => {
0 голосов
/ 03 марта 2020

Попробуйте это

  // add this to the constructor to inject zone
  constructor(public zone: NgZone, ...args) { }

И используйте зону для запуска обнаружения изменения переменной.

  interval(1000).subscribe(() => {
      // Skip if the time is not ready
      if (this.serverTime === undefined) {
        return;
      }

      // Update the time
      this.zone.run(() => this.serverTime = new Date(this.serverTime.getTime() + 1000))
      // If it's midnight, get the date again
      if (
        this.serverTime.getHours() === 0 &&
        this.serverTime.getMinutes() === 0 &&
        this.serverTime.getSeconds() < 2
      ) {
        this.getServerDate();
      }
    });
...