Angular2/4:实时刷新数据

Posted

技术标签:

【中文标题】Angular2/4:实时刷新数据【英文标题】:Angular2/4 : Refresh Data Realtime 【发布时间】:2017-12-10 09:08:38 【问题描述】:

我需要每隔一段时间刷新一个组件页面中的数据。此外,我需要在执行一些操作后刷新数据。我在服务中使用 Observables,以便在响应准备好时订阅。我正在将订阅推送到一个对象,以便我可以在ngDestroy 上清除这一点,我认为,我有以下方法可以实现相同的目标。

方法一:设置间隔

我在ngOnInit 上设置了一个间隔,它将以相等的间隔调用 refreshData。间隔对象将在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:在每次刷新调用时,都会将订阅添加到subscription 对象,这是否会增加内存使用量并且如果用户保持页面打开一段时间可能会导致浏览器崩溃?

方法2:Observable.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:要在操作方法 doAction() 之后刷新数据,调用 refreshData。那么这会创建另一个计时器链吗?

Q4:没有内存泄漏或是否存在任何其他方式,哪种方式更好?

【问题讨论】:

【参考方案1】:

你应该可以毫无问题地做到这一点:

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


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

根据this post,Angular 会自行清理。

但是,如果您要在应用中拥有实时数据流,我建议您更改组件,以便与其订阅服务的 http 请求的每个响应,不如订阅一次到组件的ngOnInit() 中服务的新可观察data$ 属性。然后,在间隔(如您所做的那样)在您的服务上调用updateData()(或在您的服务中设置间隔inside)但不要订阅。当您的服务成功获取数据时,它会将下一个值推送到其可观察的 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$ 是在您的服务中更新的可观察的 BehaviourSubject,如下所示:

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);
    )

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

【讨论】:

你能解释一下this.myService.data$吗? 谢谢。属性末尾的$有什么意义吗? 只是一个表示可观察对象的约定。见***.com/questions/37671700/…。 我试过了,但它不起作用,因为要发送请求,需要订阅。仅添加this.myService.updateData() 无效。 别忘了clearInterval()ngOnDestroy()【参考方案2】:

我只是稍微扩展了@SpaceFozzy 的答案,以便对这里的未来访客有所帮助。为了刷新数据,我使用了@SpaceFozzy 的方式。但是对于订阅,我有一个更好的方法。请看一下答案 - https://***.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;
                
            )
    


【讨论】:

感谢您展示如何使用您提到的官方方法。【参考方案3】:

请不要忘记在 ngDestroy 上清除Interval。

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

【讨论】:

@JohnPeters 阅读更多angular.io/guide/lifecycle-hooks【参考方案4】:

只需在您的项目文件夹中为 linux 用户运行此命令:

sudo sysctl fs.inotify.max_user_watches=524288 
sudo sysctl -p --system

【讨论】:

我看不出这个答案与这个问题有什么关系。

以上是关于Angular2/4:实时刷新数据的主要内容,如果未能解决你的问题,请参考以下文章

Angular2/4 电话验证

Angular2/4 mat-select 多个 ngModel

在angular2中使用lodash时出错[重复]

我可以为所有 angular2/4 项目使用一个 node_module 文件夹吗

Angular2 指令监听父组件回调或更改

在 Angular2/4/5 中,如何基于基于令牌的身份验证安全地调用 WebAPI 操作