[解決済み] Angular/RxJS `Subscription` からいつ退会すればいいのか?
質問
をいつ格納すればいいのでしょうか?
Subscription
インスタンスを起動し
unsubscribe()
の間に
ngOnDestroy
また、どのような場合に無視できるのでしょうか?
すべてのサブスクリプションを保存すると、コンポーネントコードに多くの混乱が生じます。
HTTPクライアントガイド は、このようなサブスクリプションを無視します。
getHeroes() {
this.heroService.getHeroes()
.subscribe(
heroes => this.heroes = heroes,
error => this.errorMessage = <any>error);
}
同時に ルート&ナビガイド と書かれています。
最終的には、どこかに移動する。ルーターはこのコンポーネントを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();
}
解決方法は?
TL;DR
この質問では、2種類のObservablesがあります。 有限 値と 無限 の値を指定します。
http
オブザーバブルの生成
有限
(1) 値を生成し、DOMイベントリスナーObservableのようなものは
無限
の値を指定します。
を手動で呼び出すと
subscribe
(非同期パイプを使用しない)場合は
unsubscribe
から
無限
オブザーバブルです。
を気にしないでください。 有限 は、RxJsが処理します。
ソースはこちら
-
AngularのGitterにあるRob Wormaldの回答を探し出しました。 こちら .
と述べている(わかりやすくするために再編成し、強調は私が行っている)。
もしその 単一値列 (http リクエストのような) は 手動クリーンアップが不要 (コントローラで手動でサブスクライブしていると仮定して)
と言うべきでしょう。 を完了するシーケンス httpのような単一値シーケンスはその一つです。
無限列の場合 , 退会してください 非同期パイプはあなたのためにそれを行う
また、彼は このYouTubeのビデオ オブザーバブルに関する "彼らは自分たちの後始末をする..."。 という文脈で、Observablesは コンプリート (プロミスのように、常に1つの値を生成して終了するので、常に完了します。XHRイベントリスナーをクリーンアップするために、プロミスから購読を解除することを心配したことはありませんよね?)
-
また Angular 2のラングルガイド と書かれています。
ほとんどの場合、明示的に
unsubscribe
メソッドは、早期にキャンセルする場合やObservable
は、サブスクリプションよりも長い寿命を持ちます。のデフォルトの動作はObservable
演算子は、サブスクリプションを破棄するために.complete()
または.error()
メッセージはパブリッシュされます。RxJSは、ほとんどの場合、quot;fire and forget"方式で使用されるように設計されていることに留意してください。というフレーズは、どのような場合に使われるのでしょうか? 私たちの
Observable
は、購読期間よりも長い寿命があります" が適用されますか?サブスクリプションがコンポーネント内で作成され、Observableが完了する前に(あるいは「ずっと」前に)破壊された場合に適用されます。
これを読むと、もし私たちが
http
リクエストまたは 10 個の値を出力する Observable を作成し、その前にコンポーネントが破壊される場合http
が返ってくるか、10個の値が放出されれば、まだOKです!リクエストが戻るか、10個目の値が最終的に発行されると、Observableは完了し、すべてのリソースがクリーンアップされます。
-
もし この例 へのサブスクリプションは、同じRangleガイドから見ることができます。
route.params
が必要です。unsubscribe()
というのも、これらのparams
が変化しなくなる(新しい値を出す)。この場合、ルートパラメータはまだ変化している可能性が高く(技術的にはアプリが終了するまで変化する可能性があります)、サブスクリプションで割り当てられたリソースはまだ割り当てられています。 完了 .
-
で この動画 NgEuropeのRob WormaldもRouter Observablesの配信を停止する必要はないと言っています。また、彼は
http
サービスやActivatedRoute.params
で この動画 2016年11月より -
Angularのチュートリアルです。 ルーティング編 が以下のように記載されるようになりました。
は
Router
は、提供する observable を管理し、サブスクリプションをローカライズします。サブスクリプションは、コンポーネントが破棄されるときにクリーンアップされ、メモリリークから保護されるので、ルートから退会する必要はありません。params
Observable
.以下は ディスカッション にて、Ward BellがRouter Observablesに関する説明を作成中であることを述べています。
私はNGConfでこの質問についてWard Bellと話をしました(彼が正しいと言ったこの答えも見せました)。しかし彼は、Angularのドキュメントチームがこの質問に対する解決策を持っていて、それは未発表であると言いました(彼らはそれを承認するために作業中ですが)。彼はまた、近々発表される公式な勧告で私のSOの答えを更新することができると言いました。
今後、私たち全員が使うべき解決法は
private ngUnsubscribe = new Subject();
フィールドを持つすべてのコンポーネントに
.subscribe()
の呼び出しは、クラスコード内のObservablesの呼び出しです。
次に
this.ngUnsubscribe.next(); this.ngUnsubscribe.complete();
の中で
ngOnDestroy()
メソッドを使用します。
隠し味は(既に指摘されているように
メタメーカー
を呼び出すことです。
takeUntil(this.ngUnsubscribe)
の前に、それぞれの
.subscribe()
を呼び出すことで、コンポーネントが破棄されたときにすべてのサブスクリプションがクリーンアップされることを保証します。
例
import { Component, OnDestroy, OnInit } from '@angular/core';
// RxJs 6.x+ import paths
import { filter, startWith, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { BookService } from '../books.service';
@Component({
selector: 'app-books',
templateUrl: './books.component.html'
})
export class BooksComponent implements OnDestroy, OnInit {
private ngUnsubscribe = new Subject();
constructor(private booksService: BookService) { }
ngOnInit() {
this.booksService.getBooks()
.pipe(
startWith([]),
filter(books => books.length > 0),
takeUntil(this.ngUnsubscribe)
)
.subscribe(books => console.log(books));
this.booksService.getArchivedBooks()
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe(archivedBooks => console.log(archivedBooks));
}
ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
}
注
を追加することが重要です。
takeUntil
演算子を最後の演算子として使用することで、演算子チェーン内の中間Observableによるリークを防ぐことができます。
最近だと Angularの冒険 Ben LeshとWard Bellは、コンポーネントでいつ、どのように購読を解除するかという問題について議論しています。この議論は1:05:30あたりから始まります。
ウォードが言及するのは 今、多くの機械を必要とするひどいテイクアンティルダンスがある"。 とShai Reznikが言及しています。 Angularはhttpやルーティングのようなサブスクリプションの一部を処理します。 .
それに対してBenは、AngularコンポーネントのライフサイクルイベントにObservablesをフックさせるための議論が現在行われていることに触れ、Wardは、コンポーネントの内部状態として維持されているObservablesをいつ完了するかを知る方法として、コンポーネントが購読できるライフサイクルイベントのObservableを提案しています。
とはいえ、今はほとんどソリューションが必要なので、他のリソースをいくつか紹介します。
-
への提言
takeUntil()
RxJsのコアチームメンバーであるNicholas Jamiesonによるパターン、およびそれを強制するためのTSLintルールです。 https://ncjamieson.com/avoiding-takeuntil-leaks/ -
コンポーネントインスタンス (
this
の間に自動的に配信を停止します。ngOnDestroy
: https://github.com/NetanelBasal/ngx-take-until-destroy -
AOTビルドをしないのであれば、人間工学的に少し優れた上記の別のバリエーション(しかし、我々は今、すべてAOTを行うべきである)。 https://github.com/smnbbrv/ngx-rx-collector
-
カスタムディレクティブ
*ngSubscribe
は非同期パイプのように動作しますが、テンプレート内に埋め込みビューを作成するため、テンプレート全体で「アンラップ」された値を参照することができます。 https://netbasal.com/diy-subscription-handling-directive-in-angular-c8f6e762697f
ニコラスさんのブログへのコメントで、使いすぎのことを書いていますが
takeUntil()
は、コンポーネントがあまりにも多くのことを行おうとしている兆候であり、既存のコンポーネントを
特徴
と
プレゼンテーション
コンポーネントを検討する必要があります。その上で
| async
Feature コンポーネントから Observable を
Input
というのは、Presentationalコンポーネントのサブスクリプションがどこにも必要ないことを意味します。このアプローチについてもっと読む
こちら
.
関連
-
Angular CLIでモジュール "angular-devkit/build-angular" が見つからない問題を解決する。
-
angularjs ポップアップボックスの方法1
-
[解決済み] Angular HTMLバインディング
-
[解決済み] Angular 2の "select "で新しい選択範囲を取得するにはどうすればよいですか?
-
[解決済み】Angularでファイルアップロード?
-
[解決済み] Angular CLI Error: serveコマンドはAngularプロジェクトで実行する必要がありますが、プロジェクト定義が見つかりませんでした。
-
[解決済み] Angular 4 HttpClient クエリパラメータ
-
[解決済み] Angular 2のパッシブリンク - <a href="">相当
-
[解決済み] viewchildを使用して複数のviewchildrenにアクセスする
-
[解決済み] Angular Materialダイアログエリアの外をクリックしてダイアログを閉じないようにする(Angularバージョン4.0以上で使用可能)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
angular.jsのエラーです。エラーです。[$injector:modulerr] 原因
-
Angularフレームワーク入門
-
angularjs ポップアップボックスの方法1
-
[解決済み] Angular 4: パイプ 'AsyncPipe' に対する InvalidPipeArgument: '[object Object]' です。
-
[解決済み] CLIを使ったAngular 2 - 制作のためのビルド
-
[解決済み] formGroup' は 'form' の既知のプロパティではないため、バインドできません。
-
[解決済み] Angular 2の "select "で新しい選択範囲を取得するにはどうすればよいですか?
-
[解決済み] Angular2の括弧、括弧、アスタリスクの違いは何ですか?
-
[解決済み] NgModule.schemasにCUSTOM_ELEMENTS_SCHEMAを追加してもエラーが表示される。
-
[解決済み] Angular 2でシングルトンサービスを作成するには?