914

ライフ サイクル中にインスタンスを保存してSubscription呼び出す必要があるのはいつですか? また、単純にインスタンスを無視できるのはいつですか?unsubscribe()ngOnDestroy

すべてのサブスクリプションを保存すると、コンポーネント コードに多くの混乱が生じます。

HTTP クライアント ガイドは、次のようなサブスクリプションを無視します。

getHeroes() {
  this.heroService.getHeroes()
                  .subscribe(
                     heroes => this.heroes = heroes,
                     error =>  this.errorMessage = <any>error);
}

同時に、Route & Navigation Guideは次のように述べています。

最終的には、別の場所に移動します。ルーターはこのコンポーネントを DOM から削除して破棄します。そうなる前に、自分たちで後片付けをする必要があります。具体的には、Angular がコンポーネントを破棄する前にサブスクライブを解除する必要があります。そうしないと、メモリ リークが発生する可能性があります。

Observableメソッド内でサブスクライブを解除しますngOnDestroy

private sub: any;

ngOnInit() {
  this.sub = this.route.params.subscribe(params => {
     let id = +params['id']; // (+) converts string 'id' to a number
     this.service.getHero(id).then(hero => this.hero = hero);
   });
}

ngOnDestroy() {
  this.sub.unsubscribe();
}
4

26 に答える 26

9

Angular 2 の公式ドキュメントでは、いつ購読を解除し、安全に無視できるかについて説明しています。このリンクを見てください:

https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

Parent and children communicate via a serviceという見出しの段落と、青いボックスの段落を探します。

AstronautComponent が破棄されたときに、サブスクリプションを取得してサブスクリプションを解除していることに注意してください。これはメモリ リーク ガードの手順です。AstronautComponent の有効期間はアプリ自体の有効期間と同じであるため、このアプリには実際のリスクはありません。これは、より複雑なアプリケーションでは常に当てはまるとは限りません。

このガードは、親として MissionService の有効期間を制御するため、MissionControlComponent には追加しません。

これがお役に立てば幸いです。

于 2016-06-29T11:08:04.773 に答える
4

seangwright の解決策 (編集 3) は非常に有用であるように思われるため、この機能を基本コンポーネントにパックするのも面倒であり、他のプロジェクト チームメイトに ngOnDestroy で super() を呼び出してこの機能を有効にすることを忘れないでください。

この回答は、スーパー コールから解放し、「componentDestroyed$」を基本コンポーネントのコアにする方法を提供します。

class BaseClass {
    protected componentDestroyed$: Subject<void> = new Subject<void>();
    constructor() {

        /// wrap the ngOnDestroy to be an Observable. and set free from calling super() on ngOnDestroy.
        let _$ = this.ngOnDestroy;
        this.ngOnDestroy = () => {
            this.componentDestroyed$.next();
            this.componentDestroyed$.complete();
            _$();
        }
    }

    /// placeholder of ngOnDestroy. no need to do super() call of extended class.
    ngOnDestroy() {}
}

次に、この機能を自由に使用できます。たとえば、次のようにします。

@Component({
    selector: 'my-thing',
    templateUrl: './my-thing.component.html'
})
export class MyThingComponent extends BaseClass implements OnInit, OnDestroy {
    constructor(
        private myThingService: MyThingService,
    ) { super(); }

    ngOnInit() {
        this.myThingService.getThings()
            .takeUntil(this.componentDestroyed$)
            .subscribe(things => console.log(things));
    }

    /// optional. not a requirement to implement OnDestroy
    ngOnDestroy() {
        console.log('everything works as intended with or without super call');
    }

}
于 2017-04-24T04:30:41.773 に答える
2

上記の状況への別の短い追加は次のとおりです。

  • サブスクライブされたストリームの新しい値が不要になった場合、または重要でない場合は、常にサブスクライブを解除してください。これにより、トリガーの数が大幅に減り、パフォーマンスが向上する場合があります。サブスクライブしたデータ/イベントがもう存在しないコンポーネントや、まったく新しいストリームへの新しいサブスクリプションが必要な場合 (更新など) は、サブスクライブ解除の良い例です。
于 2018-06-16T12:49:59.953 に答える
1

SPA アプリケーションのngOnDestroy関数 (angular lifeCycle) では、サブスクライブごとにサブスクライブを解除する必要があります。利点 => 状態が重くなりすぎないようにするため。

例: component1 :

import {UserService} from './user.service';

private user = {name: 'test', id: 1}

constructor(public userService: UserService) {
    this.userService.onUserChange.next(this.user);
}

使用中:

import {BehaviorSubject} from 'rxjs/BehaviorSubject';

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

component2 で:

import {Subscription} from 'rxjs/Subscription';
import {UserService} from './user.service';

private onUserChange: Subscription;

constructor(public userService: UserService) {
    this.onUserChange = this.userService.onUserChange.subscribe(user => {
        console.log(user);
    });
}

public ngOnDestroy(): void {
    // note: Here you have to be sure to unsubscribe to the subscribe item!
    this.onUserChange.unsubscribe();
}
于 2019-04-19T04:50:17.227 に答える
0

パフォーマンス上の理由から、メモリリークを回避するために、監視可能なサブスクリプションからサブスクリプションを解除することを常にお勧めします。それにはさまざまな方法があります。

ちなみに、私はほとんどの回答を読みましたが、asyncパイプについて話している人は見つかりませんでした。Angular アプリで推奨されるRxjsパターンです。これは、破棄されるコンポーネントを離れるときにサブスクリプションとサブスクリプションが自動的に提供されるためです。

実装方法の例を見つけてください

app.component.ts :

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';

import { BookService } from './book.service';
import { Book } from './book';

@Component({
   selector: 'app-observable',
   templateUrl: './observable.component.html'
})
export class AppComponent implements OnInit { 
   books$: Observable<Book[]>
   constructor(private bookService: BookService) { }
   ngOnInit(): void {
        this.books$ = this.bookService.getBooksWithObservable();
   }
} 

app.compoennt.html :

<h3>AsyncPipe with Promise using NgFor</h3>
<ul>
  <li *ngFor="let book of books$ | async" >
    Id: {{book?.id}}, Name: {{book?.name}}
  </li>
</ul>
于 2021-07-13T22:32:19.923 に答える