web-dev-qa-db-ja.com

Angular2 / 4:データをリアルタイムで更新

一定の間隔でコンポーネントページのデータを更新する必要があります。また、何らかのアクションを実行した後、データを更新する必要があります。応答の準備ができたときにサブスクライブできるように、サービスでObeservablesを使用しています。サブスクリプションをオブジェクトにプッシュして、ngDestroyでそれをクリアできるように、同じことを達成するために次の方法があると思います。

方法1:setInterval

ngOnInitに間隔を設定しました。これにより、等間隔でrefreshDataが呼び出されます。間隔オブジェクトは、clearIntervalメソッドのngOnDestroyを使用してクリアされます。

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)があります。これにより、サブスクリプションオブジェクトにもタイマーが追加されるため、サブスクリプションオブジェクトのサブスクリプションが事実上2倍になります。

Q3:アクションメソッド-doAction()の後にデータを更新するには、refreshDataが呼び出されます。それでタイマーの別のチェーンが作成されますか?

Q4:メモリリークのない、または他の方法がある場合、どちらが良い方法ですか?

15
Jithin

問題なくこれを実行できるはずです。

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

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

この投稿 Angularに従って、それ自体のクリーンアップを処理します。

ただし、、アプリでライブデータストリームを使用する場合は、次の各応答にサブスクライブするのではなく、コンポーネントを変更することをお勧めしますサービスのhttpリクエストの場合、代わりにコンポーネントのngOnInit()でサービスの新しいobservable 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$が、サービスで更新される観察可能な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);
    })
}

これにより、複数のサブスクリプションを回避し、それを必要とするすべてのコンポーネントでデータストリームを利用できるようにすることができます。

21
SpaceFozzy

@SpaceFozzyの回答を少し拡張して、将来の訪問者の役に立つようにしています。データを更新するには、@ SpaceFozzyの方法を使用しました。しかし、サブスクリプションについては、より良いアプローチを得ました。答えをご覧ください- https://stackoverflow.com/a/4117716 。そこで、サービスとコンポーネントを次のように更新しました。お役に立てれば。

私のコンポーネント

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

}
4
Jithin