購読解除とメモリリーク
takeUntilDestroyedでメモリリークを防ぎます。
「購読解除とメモリリーク」はCoddyKit上の無料Angular Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAngular Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Angular Academyコースには全4レッスンが含まれています。
メモリリークの問題
コンポーネントで長期間存続するObservableを購読したまま購読解除しないと、コンポーネントが破棄された後もコールバックが実行され続けます。これによりメモリリークが発生し、エラーや重複処理の原因になります。
手動で購読を解除する
基本的な対策は、Subscriptionを保存し、ngOnDestroyで購読を解除することです。
import { Component, OnDestroy } from '@angular/core';
import { Subscription, interval } from 'rxjs';
export class WidgetComponent implements OnDestroy {
private sub = interval(1000).subscribe(n => console.log(n));
ngOnDestroy() { this.sub.unsubscribe(); }
}複数の購読を管理する
1つのSubscriptionに.add()で子の購読をまとめると、1回のunsubscribe()ですべてを停止できます。
private subs = new Subscription();
ngOnInit() {
this.subs.add(a$.subscribe());
this.subs.add(b$.subscribe());
}
ngOnDestroy() { this.subs.unsubscribe(); }takeUntilDestroyed
AngularにはtakeUntilDestroyed()が用意されており、コンポーネントが破棄されるとストリームを自動的に完了させます。手動でngOnDestroyを記述する必要はありません。
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
export class WidgetComponent {
constructor() {
interval(1000)
.pipe(takeUntilDestroyed())
.subscribe(n => console.log(n));
}
}インジェクションコンテキストの要件
引数なしで呼び出す場合、takeUntilDestroyed()はインジェクションコンテキスト(コンストラクターなど)で実行する必要があります。コンテキストの外では、DestroyRefを明示的に渡します。
import { inject, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
const destroyRef = inject(DestroyRef);
ngOnInit() {
source$.pipe(takeUntilDestroyed(destroyRef)).subscribe();
}takeUntilパターン(従来の方法)
takeUntilDestroyedが登場する前は、ngOnDestroyで値を発行するSubjectを使うのが標準的なパターンでした。
private destroy$ = new Subject<void>();
ngOnInit() {
source$.pipe(takeUntil(this.destroy$)).subscribe();
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}完了するストリームでは後処理不要
HttpClientのリクエストは1回値を発行して完了するため、自動的に後処理されます。通常、単一のHTTP呼び出しの購読を解除する必要はありません。ただし、takeUntilDestroyedを使っても安全です。
asyncパイプに任せる
テンプレートでは、asyncパイプに購読と購読解除を自動的に任せるのが最適です。詳しくは次のレッスンで説明します。
// template:
// <div>{{ user$ | async | json }}</div>
// No manual subscribe / unsubscribe needed購読リークの兆候
ネットワークリクエストの重複、画面遷移後にも実行されるハンドラー、DevToolsで増え続けるメモリ、または「Cannot read property of destroyed view」エラーは、購読解除の漏れを示していることがよくあります。
toSignalも自動的に後処理する
ObservableをtoSignal()でsignalに変換すると、所有するコンテキストが破棄されたときに購読も自動的に解除されます。
import { toSignal } from '@angular/core/rxjs-interop';
user = toSignal(this.http.get('/api/me'));
// auto-unsubscribed on destroy方法を選ぶ
テンプレートではasyncパイプまたはtoSignalを優先し、手動で購読する場合はtakeUntilDestroyed()を使用します。必要な場合に限り、Subscriptionのコレクションを使用してください。
理解度チェック
購読解除についての理解度を確認しましょう。
まとめ:購読解除とメモリリーク
長期間存続する購読は、必ず停止処理を行ってください。
takeUntilDestroyed()は破棄時にストリームを自動的に完了させます。asyncパイプとtoSignal()は購読を自動的に管理します。- 単一のHTTP呼び出しは自動的に完了します。
次はasyncパイプを詳しく見ていきます。
よくある質問
「購読解除とメモリリーク」レッスンは無料ですか?
はい。「購読解除とメモリリーク」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Angular Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Angular Academyコースには全4レッスンが含まれています。
「購読解除とメモリリーク」で何を学びますか?
takeUntilDestroyedでメモリリークを防ぎます。 ブラウザで直接実行するハンズオンコードでAngular Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Angular Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAngular Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「購読解除とメモリリーク」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAngular Academyレッスンでコードを書いて実行できますか?
はい。すべてのAngular Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。