我有一个带定时器的服务。由于服务没有生命周期挂钩,如何销毁计时器?
这是完整的项目: https://github.com/GregFinzer/AmbientStateExample
这是服务代码。注意ngOnDestroy(它永远不会被调用)。
// 3rd party imports
import { Injectable } from '@angular/core';
import { Http, Response, RequestOptions, Headers } from '@angular/http';
import { Observable, Subscription } from 'rxjs/Rx';
import { AsyncLocalStorage } from 'angular-async-local-storage';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/do';
import {OnInit, OnDestroy} from '@angular/core';
// Our imports
import { Stock } from './stock-model';
@Injectable()
export class StockService {
private _url = 'http://finance.google.com/finance/info?client=ig&q=NASDAQ%3AAAPL,GOOG';
private _timer;
private _sub: Subscription;
private _objectKey = 'stocksObject';
private _dateKey = 'lastStockCheckDate';
private _timerInterval = 60000; // Get data from the service every 60 seconds
public lastChangeDate: Date;
constructor(private _http: Http, protected _storage: AsyncLocalStorage) {
this._timer = Observable.timer(0, this._timerInterval);
this._sub = this._timer.subscribe(tick => { this.timerTick(tick); });
}
// This will not be hit, not sure how to implement in a service
ngOnDestroy() {
console.log('Destroy timer');
this._sub.unsubscribe();
}
timerTick(tick) {
console.log('Interval hit: ' + tick);
this.processCache();
}
// Get the stocks from the local storage cache
public getFromCache(): Observable<Stock[]> {
console.error('getStockCache()');
return this._storage.getItem(this._objectKey);
}
private processCache(): void {
console.log('processCache()');
this._storage.getItem(this._dateKey).subscribe((lastCheckDate) => {
let now = new Date();
if (lastCheckDate) {
// Default last change date to the last check date
if (!this.lastChangeDate) {
this.lastChangeDate = lastCheckDate;
}
// Obey the timer interval even if the user restarts the application
if ((now.getTime() - lastCheckDate.getTime()) < this._timerInterval) {
return;
}
}
// Save the last check date
this.updateLastCheckDate();
// Get the data from the service
let servicePromise: Promise<Stock[]> = this.getDataFromService().toPromise();
// If anything changed, save to local storage
servicePromise.then((serviceData) => {
this._storage.getItem(this._objectKey).subscribe((storageData) => {
if (this.anythingChanged(serviceData, storageData)) {
this._storage.setItem(this._objectKey, serviceData)
.subscribe(() => { this.lastChangeDate = new Date(); }, () => {});
}
}, () => {});
});
}, () => {});
}
// Has anything changed from what was returned from the service vs what we have in local storage?
private anythingChanged(serviceData: Stock[], storageData: Stock[]): boolean {
console.log('anythingChanged()');
if (!storageData) {
return true;
}
if (serviceData.length !== storageData.length) {
return true;
}
for (let i = 0; i < serviceData.length; i++) {
if (serviceData[i].l_cur !== storageData[i].l_cur) {
return true;
}
}
return false;
}
// Update the last time we called the service
private updateLastCheckDate(): void {
console.error('updateLastCheckDate()');
const now = new Date();
this._storage.setItem(this._dateKey, now).subscribe(() => {}, () => {});
}
// Get stocks from the service
private getDataFromService(): Observable<Stock[]> {
console.error('getStocks()');
return this._http.get(this._url, this.getRequestOptions())
.do((data: Response) => console.log('All: ' + data.text()))
// The substr is required because Google puts in two comment characters //
.map((response: Response) => <Stock[]> JSON.parse(response.text().substr(3)));
}
// Write any errors out to the console
private handleError(error: Response) {
console.error(error);
let msg = `Error status code ${error.status} at ${error.url}`;
return Observable.throw(msg);
}
// Ensure we get JSON from the service
private getRequestOptions(): RequestOptions {
let opt: RequestOptions;
let myHeaders: Headers = new Headers;
myHeaders.append('Accept', 'application/json');
opt = new RequestOptions();
opt.headers = myHeaders;
return opt;
}
}