• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Avoid Memory Leaks in Angular When Using takeUntil with Higher-Order RxJS Operators

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155
When working with Angular and RxJS, takeUntil is a common operator for unsubscribing from observables, especially in component lifecycle management. However, if you're using takeUntil incorrectly with higher-order mapping operators like mergeMap, switchMap, concatMap, exhaustMap, you may still end up with memory leaks.

The Problem


A common mistake is placing takeUntil before a higher-order operator in your observable pipeline. This seems logical, but it doesn't always behave as expected. When takeUntil is upstream of a higher-order operator, it won't effectively unsubscribe the inner subscription created by that operator.

❌ Problematic Pattern


this.counterB$.pipe(
takeUntil(this.destroySubject),
mergeMap((value) => this.counterA$)
).subscribe(...);

In the example above, the outer observable (counterB$) is unsubscribed, but the inner observable (counterA$ from mergeMap) continues to emit values even after the component is destroyed. That’s your memory leak!

Why It Happens


Higher-order operators return new inner observables. If takeUntil is applied before them, it only stops the outer observable. But the inner one lives on.

The Correct Pattern


To ensure both outer and inner subscriptions are cleaned up properly, place takeUntil after the higher-order operator.

✅ Recommended Pattern


this.counterA$.pipe(
mergeMap((value) => this.counterB$),
takeUntil(this.destroySubject),
).subscribe(...);

In this corrected example, the whole observable chain, including inner subscriptions, is properly unsubscribed when the destroySubject emits.

Real-World Example

Service Providing Observables


@Injectable({ providedIn: 'root' })
export class TakeUntilLeakChildService {
counterA$ = interval(2000);
counterB$ = interval(1000);
}
Component Subscription


@Component({
selector: 'app-take-until-leak-child',
imports: [],
templateUrl: './take-until-leak-child.component.html',
styleUrl: './take-until-leak-child.component.scss'
})
export class TakeUntilLeakChildComponent implements OnInit, OnDestroy {

counterService = inject(TakeUntilLeakChildService);

counterA$ = this.counterService.counterA$;
counterB$ = this.counterService.counterB$;

destroySubject = new Subject();

ngOnInit(): void {
this.counterA$.pipe(
mergeMap((value) => {
return this.counterB$;
}),
takeUntil(this.destroySubject),
).subscribe((value) => {
console.log('Counter A:', value);
});

this.counterB$.pipe(
takeUntil(this.destroySubject),
mergeMap((value) => {
return this.counterA$;
}),
).subscribe((value) => {
console.log('Counter B:', value);
});
}

ngOnDestroy(): void {
console.log('Child component destroyed!');
this.destroySubject.next(true);
this.destroySubject.complete();
}
}
Console Observation


When inspecting the console, you may find that:

  • counterA$ is unsubscribed correctly.
  • counterB$ continues to emit values even after component destruction - memory leak.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Related Note on takeUntilDestroyed


The same principle applies when using Angular's takeUntilDestroyed operator. If you're using takeUntilDestroyed with higher-order mapping operators, make sure it is placed after those operators to properly unsubscribe inner observables and avoid memory leaks.

Summary


To prevent memory leaks:

  • Always place takeUntil (or takeUntilDestroyed) after higher-order operators.
  • Understand that mergeMap, switchMap, concatMap, and exhaustMap create inner observables that need cleanup.

Happy coding!


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу