Is there any destroy hook for pipes in angular2 (same as for components)?
Asked Answered
B

2

9

After investigating for several days(!?!) for a huge memory leakage of my current Angular2 application, I came up with the new discovery:

Apparently, an async pipe, which was heavily used throughout the application, was subscribing for an observable, but was never released (unsubscribed) when component and pipes where cleaned-up.

It accumulated to a number of ~11,000 observers for a single observable with very few user actions (which eventually caused the app to crash).

I need to unsubscribe the observable, and in order to do that I need a hook for destruction, similar to ngOnDestroy, but for pipes.

Is there any such hook, or if not, how would you suggest to unsubscribe?

Blavatsky answered 1/6, 2016 at 21:10 Comment(0)
M
17

If you take a look at the async pipe code, you can see that they are using ngOnDestroy just like how would you do it in a directive.

snippet from AsyncPipe code:

@Pipe({name: 'async', pure: false})
@Injectable()
export class AsyncPipe implements OnDestroy {
  ...

  ngOnDestroy(): void {
    if (isPresent(this._subscription)) {
      this._dispose();
    }
  }
  ...
}

The key is using: pure:false,

From OnDestroy

To create a stateful Pipe, you should implement this interface and set the pure parameter to false in the PipeMetadata.

A stateful pipe may produce different output, given the same input. It is likely that a stateful pipe may contain state that should be cleaned up when a binding is destroyed. For example, a subscription to a stream of data may need to be disposed, or an interval may need to be cleared.

Mozzarella answered 1/6, 2016 at 21:43 Comment(6)
That could have been nice if it worked, but debugging ngOnDestroy indicates that pipe own't ever enter this method on destruction (or ever). Did you see it working yourself?Blavatsky
@ChenEshchar, I just created a plunk to test it and it works. Click the button to show/hide the component and watch the console.Mozzarella
I see your plunk and I see the docs but for me, it won't enter the ngOnDestroy. It might be the case since it's...not released for GC. I will investigate a little bit further, but in the meantime, thanks for your help.Blavatsky
@ChenEshchar If you add your pipe code to your question, I might be able to see where you went wrong.Mozzarella
I don't know from which Angular version, but onDestroy can be used even with pure pipe.Palish
As of now, tested on Angular 15, the ngOnDestroy lifecycle hook is called when a component is destroyed, or in the case of show and hide operations as well.Lardaceous
C
0

Since Angular 16 we have takeUntilDestroyed pipe. It must be used either in constructor or by passing DestroyRef. The second case also allows us to react to a destruction of some other component.

export class DemoComponent {
  protected destroyRef = inject(DestroyRef);

  ngOnInit(): void {
    this.fooObservable.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((value) => {
      ...do something
    });
  }
}
Cancellation answered 17/7, 2023 at 7:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.