Jak stworzyć timer w Angular2

97

Potrzebuję timera w Angular 2, który tyka po pewnym czasie i wykonuję jakieś zadanie (może być wywołanie niektórych funkcji).

Jak to zrobić w Angular 2?

kuntal
źródło
2
Dołącz tylko tyle kodu, aby umożliwić innym odtworzenie problemu. Aby uzyskać pomoc, przeczytaj artykuł Jak utworzyć przykład minimalny, kompletny i weryfikowalny. Jeśli możliwe jest utworzenie rzeczywistego przykładu problemu, do którego można utworzyć link (na przykład w witrynie sqlfiddle.com lub jsbin.com ), zrób to - ale także umieść kod w samym pytaniu. Nie każdy ma dostęp do zewnętrznych witryn, a linki mogą z czasem ulec uszkodzeniu.
Prasad
15
W rzeczywistości jest to bardzo pomocne pytanie. Obserwacje są ważne do nauczenia się i wykorzystania. Nawet jeśli użytkownik nie miał kodu do przejścia z tego pytania, będzie pomocny dla innych.
Winnemucca,
Ten komentarz mieści się w tym samym przedziale, ale żadna z poprzednich 2 osób nie pomogła, właśnie skomentowała pytanie ... Najwyraźniej ludzie ponownie używają setTimeout.
rbnzdave
setTimeout jest naprawdę oldschoolowy
Philip
2
let this._timer = setInterval (() => this.getWidgetData (), 10000); i upewnij się, że wywołałeś clearInterval (this._timer); on
Destroy

Odpowiedzi:

129

Oprócz wszystkich poprzednich odpowiedzi zrobiłbym to za pomocą RxJS Observables

sprawdź Observable.timer

Oto przykładowy kod, który rozpocznie się po 2 sekundach, a następnie będzie zaznaczony co sekundę:

import {Component} from 'angular2/core';
import {Observable} from 'rxjs/Rx';

@Component({
    selector: 'my-app',
    template: 'Ticks (every second) : {{ticks}}'
})
export class AppComponent {
  ticks =0;
  ngOnInit(){
    let timer = Observable.timer(2000,1000);
    timer.subscribe(t=>this.ticks = t);
  }
}

A oto pracujący plunker

Aktualizacja Jeśli chcesz wywołać funkcję zadeklarowaną w klasie AppComponent, możesz wykonać jedną z następujących czynności:

** Zakładając, że funkcja, którą chcesz wywołać, nazywa się func ,

ngOnInit(){
    let timer = Observable.timer(2000,1000);
    timer.subscribe(this.func);
}

Problem z powyższym podejściem polega na tym, że jeśli wywołasz „this” wewnątrz funkcji func, odniesie się ono do obiektu subskrybenta zamiast do obiektu AppComponent, co prawdopodobnie nie jest tym, czego chcesz.

Jednak w poniższym podejściu tworzysz wyrażenie lambda i wywołujesz w nim funkcję func . W ten sposób wywołanie func nadal znajduje się w zakresie AppComponent. Moim zdaniem to najlepszy sposób na zrobienie tego.

ngOnInit(){
    let timer = Observable.timer(2000,1000);
    timer.subscribe(t=> {
        this.func(t);
    });
}

sprawdź ten plunker pod kątem działającego kodu.

Abdulrahman Alsoghayer
źródło
Czy powinienem przekazać funkcję do `timer.subscribe (t => this.ticks = t);`, która jest wywoływana w każdym tiku?
kuntal
@matrixwebtech Tak, 't => this.ticks = t' jest wyrażeniem lambda, dokładnie takim samym jak 'function (t) {this.ticks = t}'
Abdulrahman Alsoghayer
Próbuję timer.subscribe (nazwa funkcji () {console.log ("hhhhhh")}); który działa, ale jak wywołuję funkcję, która zadeklarowała oddzielnie ngOnInit () {let timer = Observable.timer (2000,1000); timer.subscribe (function () {this.fun ();}); } fun () {console.log ("hhhhhh")}
kuntal
@matrixwebtech, sprawdź przykłady w mojej zaktualizowanej odpowiedzi.
Abdulrahman Alsoghayer
1
@Notflip Pod maską, timerwydaje się , że używa setInterval(). Ale możesz przekazać animationFrameharmonogram (który używa requestAnimationFrame()), aby go używał zamiast domyślnego asyncharmonogramu. Wszystko, co musisz zrobić, to Observable.timer(*,*,Scheduler.animationFrame)dane, import {Scheduler} from ‘rxjs’chociaż wydaje się, timerże nie działa. Nadal wydaje się używać setInterVal(). Jednak w przypadku innych rodzajów obserwowalnych, takich jak Observable.range(0,1000,Scheduler.animationFrame), z requestAnimationFramepewnością jest używany. Jeśli chodzi o wydajność, nie mogę ci teraz odpowiedzieć na pewno.
Abdulrahman Alsoghayer
79

Innym rozwiązaniem jest użycie TimerObservable

TimerObservable jest podklasą Observable.

import {Component, OnInit, OnDestroy} from '@angular/core';
import {Subscription} from "rxjs";
import {TimerObservable} from "rxjs/observable/TimerObservable";

@Component({
  selector: 'app-component',
  template: '{{tick}}',
})
export class Component implements OnInit, OnDestroy {

  private tick: string;
  private subscription: Subscription;

  constructor() {
  }

  ngOnInit() {
    let timer = TimerObservable.create(2000, 1000);
    this.subscription = timer.subscribe(t => {
      this.tick = t;
    });
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

PS: Nie zapomnij wypisać się.

Philip
źródło
3
kluczem jest anulowanie subskrypcji
Tucker
jak zrezygnować z subskrypcji? i kiedy?
Miguel Stevens,
1
@Notflip ngOnDestroy jest wywoływane podczas deinicjalizacji komponentu: this.subscription.unsubscribe();unsubscribes.
Philip
Jak możesz korzystać z this.subscription bez odwoływania się do tego powyżej?
Winnemucca
2
Jak możesz go wstrzymać i ponownie uruchomić?
Dani
11
import {Component, View, OnInit, OnDestroy} from "angular2/core";

import { Observable, Subscription } from 'rxjs/Rx';

@Component({

})
export class NewContactComponent implements OnInit, OnDestroy {

    ticks = 0;
    private timer;
    // Subscription object
    private sub: Subscription;


    ngOnInit() {
        this.timer = Observable.timer(2000,5000);
        // subscribing to a observable returns a subscription object
        this.sub = this.timer.subscribe(t => this.tickerFunc(t));
    }
    tickerFunc(tick){
        console.log(this);
        this.ticks = tick
    }

    ngOnDestroy(){
        console.log("Destroy timer");
        // unsubscribe here
        this.sub.unsubscribe();

    }


}
Unnikrishnan Parameswaran
źródło
3
To nie dodaje niczego, co nie zostało wyjaśnione w innych odpowiedziach, czy nie?
Günter Zöchbauer
6

Z rxjs 6.2.2 i Angular 6.1.7 otrzymywałem:

Observable.timer is not a function

błąd. Ten problem został rozwiązany przez zastąpienie Observable.timerz timer:

import { timer, Subscription } from 'rxjs';

private myTimerSub: Subscription;    

ngOnInit(){    
    const ti = timer(2000,1000);    
    this.myTimerSub = ti.subscribe(t => {    
        console.log("Tick");    
    });    
}    

ngOnDestroy() {    
    this.myTimerSub.unsubscribe();    
}
Matt Saunders
źródło
3
Aby zrezygnować z subskrypcji, musisz mieć zmienną subskrypcji, taką jak @ alexis-poo powyżej. Zobacz: stackoverflow.com/questions/40181169/… . Opieram się na twojej odpowiedzi, która nie działa tak, jak napisano w tym względzie.
Reid,
Uwielbiam tego faceta, który zawsze aktualizuje posty do najnowszych wersji Angulara ... Za każdym razem tyle zmagań z AngularJS i Angular. Dzięki stary!
schody łańcuchowe
4

Możesz po prostu użyć narzędzia setInterval i użyć funkcji strzałki jako wywołania zwrotnego, aby thiswskazywała na instancję komponentu.

Na przykład:

this.interval = setInterval( () => { 
    // call your functions like 
    this.getList();
    this.updateInfo();
});

Wewnątrz haka cyklu życia ngOnDestroy wyczyść interwał.

ngOnDestroy(){
    clearInterval(this.interval);
}
Shivang Gupta
źródło
3

Napotkałem problem polegający na tym, że musiałem użyć timera, ale musiałem wyświetlić je w tym samym czasie w 2 komponentach, na tym samym ekranie. Utworzyłem timer obserwowalny w usłudze. Zasubskrybowałem licznik czasu w obu komponentach i co się stało? Nie zostanie zsynchronizowany, ponieważ nowa subskrypcja zawsze tworzy własny strumień.

Chciałabym powiedzieć, że jeśli planujesz używać jednego timera w kilku miejscach, zawsze umieszczaj go .publishReplay(1).refCount() na końcu Observera, ponieważ za każdym razem będzie on publikował z niego ten sam strumień.

Przykład:

this.startDateTimer = Observable.combineLatest(this.timer, this.startDate$, (localTimer, startDate) => {
  return this.calculateTime(startDate);
}).publishReplay(1).refCount();
xyztdanid4
źródło
czy możesz podzielić się swoim wdrożeniem?
Nitish Kumar
1

Znalazłem pakiet npm, który ułatwia to dzięki RxJS jako usłudze.

https://www.npmjs.com/package/ng2-simple-timer

Możesz `` zasubskrybować '' istniejący zegar, aby nie tworzyć miliardów zegarów, jeśli używasz go wiele razy w tym samym komponencie.

Simon_Weaver
źródło
1

Jeśli chcesz uruchomić metodę w ngOnInit, możesz zrobić coś takiego:

zaimportuj te 2 biblioteki z RXJS:

import {Observable} from 'rxjs/Rx';
import {Subscription} from "rxjs";

Następnie zadeklaruj licznik czasu i subskrypcję prywatną, przykład:

timer= Observable.timer(1000,1000); // 1 second for 2 seconds (2000,1000) etc
private subscription: Subscription;

Ostatnia, ale nie mniej ważna metoda uruchamiania po zatrzymaniu timera

ngOnInit() {
  this.subscription = this.timer.subscribe(ticks=> {
    this.populatecombobox();  //example calling a method that populates a combobox
    this.subscription.unsubscribe();  //you need to unsubscribe or it will run infinite times
  });
}

To wszystko, Angular 5

Alexis Poo
źródło
0
Set Timer and auto call service after certain time
// Initialize from ngInit
ngOnInit(): void {this.getNotifications();}

getNotifications() {
    setInterval(() => {this.getNewNotifications();
    }, 60000);  // 60000 milliseconds interval 
}
getNewNotifications() {
    this.notifyService.getNewNotifications().subscribe(
        data => { // call back },
        error => { },
    );
}
Nazmul Nadim
źródło