Отмена подписок и утечки памяти
Избегайте утечек с помощью takeUntilDestroyed.
«Отмена подписок и утечки памяти» — бесплатный урок Angular Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения 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(); }
}Управление несколькими подписками
Один объект Subscription может объединить дочерние подписки с помощью .add(), после чего один вызов 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 стандартный шаблон использовал Subject, который выдавал значение в ngOnDestroy.
private destroy$ = new Subject<void>();
ngOnInit() {
source$.pipe(takeUntil(this.destroy$)).subscribe();
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}Завершающиеся потоки не требуют очистки
Запросы HttpClient выдают значение один раз, а затем завершаются, поэтому самостоятельно освобождают ресурсы. Обычно отписываться от отдельного HTTP-запроса не нужно, хотя takeUntilDestroyed по-прежнему безопасен.
Асинхронный конвейер делает это за Вас
Для шаблонов лучше всего позволить конвейеру async автоматически выполнять подписку и отписку. Подробнее об этом рассказывается в следующем уроке.
// template:
// <div>{{ user$ | async | json }}</div>
// No manual subscribe / unsubscribe neededПризнаки утечки подписки
Повторяющиеся сетевые запросы, срабатывание обработчиков после перехода на другую страницу, рост потребления памяти в инструментах разработчика или ошибки «Cannot read property of destroyed view» часто указывают на забытую отписку.
toSignal тоже автоматически освобождает ресурсы
Преобразование observable в сигнал с помощью toSignal() также автоматически выполняет отписку при уничтожении контекста-владельца.
import { toSignal } from '@angular/core/rxjs-interop';
user = toSignal(this.http.get('/api/me'));
// auto-unsubscribed on destroyВыбор подхода
В шаблонах отдавайте предпочтение конвейеру async или toSignal; для ручных подписок используйте takeUntilDestroyed(); к объединению подписок прибегайте только при необходимости.
Быстрая проверка
Проверьте, насколько хорошо Вы поняли отписку.
Повторение: отписка и утечки памяти
Всегда завершайте подписки с длительным временем жизни.
takeUntilDestroyed()автоматически завершает поток при уничтожении.- Конвейер
asyncиtoSignal()управляют подписками за Вас. - Отдельные HTTP-запросы завершаются самостоятельно.
Далее: подробное изучение конвейера async.
Часто задаваемые вопросы
Урок «Отмена подписок и утечки памяти» бесплатный?
Да — полный текст урока «Отмена подписок и утечки памяти» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Angular Academy, подпишись на CoddyKit PRO. Курс Angular Academy содержит 4 уроков всего.
Чему я научусь в уроке «Отмена подписок и утечки памяти»?
Избегайте утечек с помощью takeUntilDestroyed. Ты практикуешь Angular Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Angular Academy?
Предыдущий опыт не требуется. Angular Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Отмена подписок и утечки памяти»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Angular Academy?
Да. Каждый урок Angular Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Наблюдаемые последовательности и подписки
- Субъекты и BehaviorSubject
- Отмена подписок и утечки памяти
- Асинхронный конвейер