Angular でサブスクリプションをキャンセルするタイミングの詳細な説明

小云云
リリース: 2017-12-12 11:05:29
オリジナル
1592 人が閲覧しました

Observable オブジェクトをサブスクライブするとき、またはイベント リスナーをセットアップするとき、ある時点でサブスクリプション解除操作を実行してオペレーティング システムのメモリを解放する必要があることはご存知かもしれません。そうしないと、アプリケーションでメモリ リークが発生する可能性があります。

ngOnDestroy ライフサイクル フックでサブスクリプション解除操作を手動で実行する必要がある一般的なシナリオをいくつか見てみましょう。この記事では主に、Angular でサブスクリプションをキャンセルするタイミングについての簡単な議論を紹介します。これが非常に優れていると思いますので、参考にしてください。編集者をフォローして見てみましょう。皆さんのお役に立てれば幸いです。

手動リリースリソースシナリオ

Form


export class TestComponent {

 ngOnInit() {
  this.form = new FormGroup({...});
  // 监听表单值的变化
  this.valueChanges = this.form.valueChanges.subscribe(console.log);
  // 监听表单状态的变化              
  this.statusChanges = this.form.statusChanges.subscribe(console.log);
 }

 ngOnDestroy() {
  this.valueChanges.unsubscribe();
  this.statusChanges.unsubscribe();
 }
}
ログイン後にコピー


上記の解決策は、他のフォームコントロールにも適用できます。

ルーティング


export class TestComponent {
 constructor(private route: ActivatedRoute, private router: Router) { }

 ngOnInit() {
  this.route.params.subscribe(console.log);
  this.route.queryParams.subscribe(console.log);
  this.route.fragment.subscribe(console.log);
  this.route.data.subscribe(console.log);
  this.route.url.subscribe(console.log);
  
  this.router.events.subscribe(console.log);
 }

 ngOnDestroy() {
  // 手动执行取消订阅的操作
 }
}
ログイン後にコピー


レンダラサービス


export class TestComponent {
 constructor(
  private renderer: Renderer2, 
  private element : ElementRef) { }

 ngOnInit() {
  this.click = this.renderer
    .listen(this.element.nativeElement, "click", handler);
 }

 ngOnDestroy() {
  this.click.unsubscribe();
 }
}
ログイン後にコピー


Infinite Observables

interval()またはfromEvenを使用する場合t() 演算子を使用すると、無限の Observable オブジェクトが作成されます。この場合、それらを使用する必要がなくなったら、リソースを手動で購読解除して解放する必要があります。


export class TestComponent {
 constructor(private element : ElementRef) { }

 interval: Subscription;
 click: Subscription;

 ngOnInit() {
  this.interval = Observable.interval(1000).subscribe(console.log);
  this.click = Observable.fromEvent(this.element.nativeElement, 'click')
              .subscribe(console.log);
 }

 ngOnDestroy() {
  this.interval.unsubscribe();
  this.click.unsubscribe();
 }
}
ログイン後にコピー


Redux Store


export class TestComponent {

 constructor(private store: Store) { }

 todos: Subscription;

 ngOnInit() {
   /**
   * select(key : string) {
   *  return this.map(state => state[key]).distinctUntilChanged();
   * }
   */
   this.todos = this.store.select('todos').subscribe(console.log); 
 }

 ngOnDestroy() {
  this.todos.unsubscribe();
 }
}
ログイン後にコピー


リソースシナリオを手動で解放する必要はありません

AsyncPipe


@Component({
 selector: 'test',
 template: `<todos [todos]="todos$ | async"></todos>`
})
export class TestComponent {
 constructor(private store: Store) { }
 
 ngOnInit() {
   this.todos$ = this.store.select(&#39;todos&#39;);
 }
}
ログイン後にコピー


コンポーネントが破棄、非同期 パイプラインは、メモリ リークのリスクを回避するために、サブスクリプション解除操作を自動的に実行します。

Angular AsyncPipe ソース コード スニペット


@Pipe({name: &#39;async&#39;, pure: false})
export class AsyncPipe implements OnDestroy, PipeTransform {
 // ...
 constructor(private _ref: ChangeDetectorRef) {}

 ngOnDestroy(): void {
  if (this._subscription) {
   this._dispose();
  }
 }
}
ログイン後にコピー


@HostListener


export class TestDirective {
 @HostListener(&#39;click&#39;)
 onClick() {
  ....
 }
}
ログイン後にコピー


イベント リスナーを追加するときに @HostListener デコレータを使用する場合、キャンセルできません手動で。イベントリスニングを手動で削除する必要がある場合は、次のメソッドを使用できます:


// subscribe
this.handler = this.renderer.listen(&#39;document&#39;, "click", event =>{...});

// unsubscribe
this.handler();
ログイン後にコピー


Finite Observable

HTTP サービスまたはタイマー Observable オブジェクトを使用する場合、手動でサブスクライブを解除する必要はありません。 。


export class TestComponent {
 constructor(private http: Http) { }

 ngOnInit() {
  // 表示1s后发出值,然后就结束了
  Observable.timer(1000).subscribe(console.log);
  this.http.get(&#39;http://api.com&#39;).subscribe(console.log);
 }
}
ログイン後にコピー


タイマーオペレーター

オペレーター署名


コードをコピーしますコードは次のとおりです:


public static timer(initialDelay:number | Date, period:number) 、スケジューラー: Scheduler ): Observable


Operator function

timer は、特定の時間間隔で無限の自動増加シーケンスを発行する Observable を返します。この間隔はユーザーが選択します。

演算子の例


// 每隔1秒发出自增的数字,3秒后开始发送
var numbers = Rx.Observable.timer(3000, 1000);
numbers.subscribe(x => console.log(x));

// 5秒后发出一个数字
var numbers = Rx.Observable.timer(5000);
numbers.subscribe(x => console.log(x));
ログイン後にコピー


最後の提案

Subscribe() メソッドの呼び出しはできるだけ少なくする必要があります。Subject について詳しくは、「RxJS: Don't Unsubscribe」の記事をご覧ください。

具体的な例は次のとおりです:


export class TestComponent {
 constructor(private store: Store) { }

 private componetDestroyed: Subject = new Subject();
 todos: Subscription;
 posts: Subscription;

 ngOnInit() {
   this.todos = this.store.select(&#39;todos&#39;)
           .takeUntil(this.componetDestroyed).subscribe(console.log); 
           
   this.posts = this.store.select(&#39;posts&#39;)
           .takeUntil(this.componetDestroyed).subscribe(console.log); 
 }

 ngOnDestroy() {
  this.componetDestroyed.next();
  this.componetDestroyed.unsubscribe();
 }
}
ログイン後にコピー


takeUntilオペレータ

オペレータ署名


public takeUntil(notifier: Observable): Observable<T>
ログイン後にコピー


オペレータ関数

E mit source Observable ノーティファイア Observable が値を発行するまでに発行される値。

演算子の例


var interval = Rx.Observable.interval(1000);
var clicks = Rx.Observable.fromEvent(document, &#39;click&#39;);
var result = interval.takeUntil(clicks);

result.subscribe(x => console.log(x));
ログイン後にコピー


関連する推奨事項:

AngularJS でのフォーム検証の詳細な説明

AngularJS_Angular でのカスタム ディレクティブの使用の詳細な説明JS

AngularJSの詳しい説明filters_AngularJS を定義する

以上がAngular でサブスクリプションをキャンセルするタイミングの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート