Angular 2で、メモリ管理に関する特定の落とし穴はありますか?
リークの可能性を回避するためにコンポーネントの状態を管理するためのベストプラクティスは何ですか?
具体的には、ngOnDestroy
メソッドで HTTPオブザーバブルからのサブスクライブを解除 を見た人がいます。私はいつもそれをするべきですか?
Angular 1.Xでは、$scope
が破棄され、その上のすべてのリスナーも自動的に破棄されます。 Angular 2個のコンポーネントのオブザーバブルについてはどうですか?
@Component({
selector: 'library',
template: `
<tr *ngFor="#book of books | async">
<td>{{ book.title.text }}</td>
<td>{{ book.author.text }}</td>
</tr>
`
})
export class Library {
books: Observable<any>;
constructor(private backend: Backend) {
this.books = this.backend.get('/texts'); // <-- does it get destroyed
// with the component?
}
};
@katspaughからのリクエスト
あなたの特定のケースでは、それは非同期パイプの仕事なので手動で購読を解除する必要はありません。
ソースコード でAsyncPipeを確認します。簡潔にするために、関連するコードを投稿しています
class AsyncPipe implements PipeTransform, OnDestroy {
// ...
ngOnDestroy(): void {
if (isPresent(this._subscription)) {
this._dispose();
}
}
ご覧のとおり、非同期パイプはOnDestroyを実装しており、それが破棄されると、サブスクリプションがあるかどうかを確認して削除します。
あなたはこの特定のケースで車輪を再発明することになります(自分自身を繰り返し申し訳ありません)。これは、あなたが参照したような他のケースでは自分で購読を解除できない/すべきでないという意味ではありません。その場合、ユーザーはコンポーネント間でObservableを渡して通信するため、手動でサブスクライブを解除することをお勧めします。
フレームワークがaliveサブスクリプションを検出し、コンポーネントが破棄されたときにそれらのサブスクリプションを自動的にサブスクライブ解除できるかどうかは知りません。もちろん、さらに調査が必要になります。
これが非同期パイプについて少し明確になれば幸いです。
Http.get()の後のように、標準のサブスクリプションを解除する必要はありません。ただし、カスタムサブジェクトのサブスクリプションを解除する必要があります。コンポーネントがあり、その中にサービスのサブジェクトをサブスクライブしている場合、そのコンポーネントを表示するたびに、新しいサブスクリプションがサブジェクトに追加されます。
これをチェックしてください: コンポーネントを「クリーン」にするための良い解決策
私の個人的なアプローチ-私のすべてのコンポーネントは、このNiceクラスから拡張されています。
import { OnDestroy, OnInit } from '@angular/core';
import { Subject } from 'rxjs/Subject';
/**
* A component that cleans all subscriptions with oneself
* https://stackoverflow.com/questions/38008334/angular-rxjs-when-should-i-unsubscribe-from-subscription
* @class NeatComponent
*/
export abstract class NeatComponent implements OnDestroy, OnInit {
// Add '.takeUntil(this.ngUnsubscribe)' before every '.subscrybe(...)'
// and this subscriptions will be cleaned up on component destroy.
protected ngUnsubscribe: Subject<any> = new Subject();
public ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
public ngOnInit(){}
}
そして、私は単にコンストラクタにsuper()呼び出しを追加し、すべてのサブスクライブの前に。takeUntil(this.ngUnsubscribe)を追加します:
import { NeatComponent } from '../../types/neat.component';
@Component({
selector: 'category-selector',
templateUrl: './category-selector.component.pug'
})
export class CategorySelectorComponent extends NeatComponent {
public constructor(
private _shopService: ShopsService
) { super(); }
public ngOnInit() {
this._shopService.categories.takeUntil(this.ngUnsubscribe)
.subscribe((categories: any) => {
// your code here
})
}
}