提问者:小点点

Angular2/4:实时刷新数据


我需要在一段时间内刷新组件页面中的数据。我还需要在执行一些操作后刷新数据。我在服务中使用Obeservables,以便在响应准备就绪时订阅。我正在将订阅推送到一个对象,以便我可以在ngDestroy上清除它,我想,我有以下方法来实现相同的。

方法一:setInterval

我在ngOnInit上设置了一个间隔,它将以相等的间隔调用刷新数据。间隔对象将在ngOnDestroy方法中使用clearInterval清除。

export class MyComponent implements OnInit, OnDestroy {
    private subscription: Subscription = new Subscription();

    data: any;
    interval: any;

    ngOnInit() {
        this.refreshData();
        this.interval = setInterval(() => { 
            this.refreshData(); 
        }, 5000);
    }

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

    refreshData(){
        this.subscription.add(
            this.myService.getData()
                .subscribe(data => {
                    this.data = data;
                })
        );
    }

    doAction(){
        this.subscription.add(
            this.myService.doAction()
                .subscribe(result => {
                    if(result === true){
                        this.refreshData();
                    }
                })
        );
    }
}

Q1:在每次刷新调用订阅将被添加到订阅对象,这将增加内存使用,并可能崩溃浏览器,如果用户保持页面打开一段时间?

方法2:可观察. timer

此方法使用将在刷新数据后创建的计时器。

export class MyComponent implements OnInit, OnDestroy {
    private subscription: Subscription = new Subscription();

    data: any;

    ngOnInit() {
        this.refreshData();
    }

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

    refreshData(){
        this.subscription.add(
            this.myService.getData()
                .subscribe(data => {
                    this.data = data;
                    this.subscribeToData();
                })
        );
    }

    subscribeToData(){
        this.subscription.add(
            Observable.timer(10000).subscribe(() => this.refreshData())
        );
    }

    doAction(){
        this.subscription.add(
            this.myService.doAction()
                .subscribe(result => {
                    if(result === true){
                        this.refreshData();
                    }
                })
        );
    }
}

Q2:我在这里有同样的问题(Q1)。这样,将计时器也添加到订阅对象中,因此实际上订阅对象中的订阅加倍。

Q3:为了在action方法-doAction()之后刷新数据,将调用刷新数据。那么这会创建另一个计时器链吗?

Q4:没有内存泄漏的更好方法是什么,或者是否存在其他方法?


共3个答案

匿名用户

您应该能够毫无问题地做到这一点:

ngOnInit() {
    this.refreshData();
    this.interval = setInterval(() => { 
        this.refreshData(); 
    }, 5000);
}

refreshData(){
    this.myService.getData()
        .subscribe(data => {
            this.data = data;
        })
    );
}

根据这篇文章,Angular将自行清理。

但是,如果您的应用程序中有一个实时数据流,我建议更改您的组件,这样您就可以在组件的ngOnInit()中订阅一次服务的新可观察data$属性,而不是订阅服务超文本传输协议请求的每个响应。然后,在间隔(就像您正在做的那样)调用服务上的updateData()(或在服务中设置间隔),但不要订阅。当您的服务成功获取数据时,它会将下一个值推送到其可观察data$属性,从而为您提供来自服务的数据流,您可以在应用程序的任何位置做出反应。

ngOnInit() {
    this.myService.data$.subscribe(data => { // subscribe once to the data stream
        this.data = data;
    })

    this.refreshData();
    this.interval = setInterval(() => { 
        this.refreshData(); 
    }, 5000);
}

refreshData(){
    this.myService.updateData(); // simply signal for the service to update its data stream
}

使用myService.data$作为服务中更新的可观察行为主题,如下所示:

public data$: BehaviorSubject<any> = new BehaviorSubject({});

updateData() {
    let data = this.http.get('http://www.data.com').map((data)=>{
        return data.json();
    }).do((data)=>{
        this.data$.next(data);
    })
}

这样您就可以避免多个订阅并使数据流可用于任何需要它的组件。

匿名用户

我只是将@SpaceFozzy的回答扩展了一点,以便对未来的访问者有所帮助。为了刷新数据,我使用了@SpaceFozzy的方式。但是对于订阅,我有一个更好的方法。请看看答案-https://stackoverflow.com/a/41177163.所以我更新了我的服务和组件如下。希望这有所帮助。

我的组件

import { Subject } from 'rxjs/Subject';

export class MyComponent implements OnInit, OnDestroy {
    private unsubscribe: Subject = new Subject();

    data: any;
    interval: any;

    ngOnInit() {
        this.refreshData();
        if(this.interval){
            clearInterval(this.interval);
        }
        this.interval = setInterval(() => {
            this.refreshData();
        }, 10000);


        this.myService.data$.takeUntil(this.unsubscribe)
            .subscribe(data => {
                this.data = data;
            });

    }

    ngOnDestroy() {
        this.unsubscribe.next();
        this.unsubscribe.complete();
    }

    refreshData(){
        this.myService.updateData()
            .takeUntil(this.unsubscribe)
            .subscribe();
    }

    doAction(){
        this.subscription.add(
            this.myService.doAction()
                .subscribe(result => {
                    if(result === true){
                        this.refreshData();
                    }
                })
        );
    }
}

我的服务

import { Observable, BehaviorSubject } from 'rxjs';

@Injectable()
export class MyService {
    private dataSubject: BehaviorSubject<YourDataModel[]> = new BehaviorSubject([]);

    data$: Observable<YourDataModel[]> = this.dataSubject.asObservable();

    updateData(): Observable<any>  {
        return this.getData().do((data) => {
            this.dataSubject.next(data);
        });
    }

    // My data is an array of model objects
    getData(): Observable<YourDataModel[]>{
        return this.http.get('/path')
            .map((response: Response) => {
                let data = response.json() && response.json().your_data_objects;
                if(data){
                    return data;
                }
            })
    }

}

匿名用户

请不要忘记清除ngDestroy上的间隔。

    ngOnDestroy() {
        this.unsubscribe.next();
        this.unsubscribe.complete();
        clearInterval(this.interval);
    }