Common RXJS usage errors

Remember to unsubscribe

What is a Subscription? A Subscription is an object that represents a disposable resource, usually the execution of an Observable. A Subscription has one important method,unsubscribe, that takes no argument and just disposes the resource held by the subscription

An Observable that subscribes is destroyed to free memory only in the following cases

- Observable sends the value. Execute Observable.onComplete(). - Observable error occurs. Execute observable. OnError(). - The subscriber unsubscribes, subscription. Unsubscribe ().Copy the code

The first two are released automatically, while the last one requires the user to release it manually.

export class MemComponent implements OnInit {

  constructor(private router: Router) { }

  ngOnInit(): void {
    // Each time a component is initialized, it listens for routing events and continues to listen after the component is destroyed, causing a memory leak.
    this.router.events
      .pipe(filter(e= > e instanceof NavigationEnd))
      .subscribe(() = > {
        console.log('End of navigation'); }); }}Copy the code

It’s clear that in most cases in ng projects we don’t need to release manually. Angular does a lot for us:

  • Angular implements Observables returned from Http Requests through HttpClient, and subscribes to these Observables to receive data returned from the API without calling unsubscribe().

    export class XHRConnection implements Connection {
      constructor(req: Request, browserXHR: BrowserXhr, baseResponseOptions? : ResponseOptions) {
        this.request = req;
        this.response = new Observable<Response>((responseObserver: Observer<Response>) = >{... .const onLoad = () = > {
            const response = new Response(responseOptions);
            response.ok = isSuccess(status);
            if (response.ok) {
              responseObserver.next(response);
              // response sucess, then call complete to end current responseObserver
              responseObserver.complete();
              return;
            }
            responseObserver.error(response);
          };
          const onError = (err: ErrorEvent) = >{... .// response error, then call error to end current responseObserver
            responseObserver.error(newResponse(responseOptions)); }; }}Copy the code
  • Angular AsyncPipe does not need to call unsubscribe() to unsubscribe.

    @Injectable(a)@Pipe({name: 'async'.pure: false})
    export class AsyncPipe implements OnDestroy.PipeTransform {...private _subscription: SubscriptionLike|Promise<any>|null = null; .constructor(private _ref: ChangeDetectorRef) {}
    
      ngOnDestroy(): void {
        if (this._subscription) {
          this._dispose(); }}... .Copy the code

    In addition to calling unsubscribe, we can use take, takeWhile, first,takeUntil in this example we use the more common takeUntil

    export class MemComponent implements OnInit.OnDestroy {
          
      destory$ = new Subject();
    
      constructor(private router: Router) { }
    
    
      ngOnInit(): void {
        this.router.events
          .pipe(filter(e= > e instanceof NavigationStart))
          .subscribe(() = > {
            console.log('Navigation started');
          });
        this.router.events
          .pipe(
            filter(e= > e instanceof NavigationEnd),
            takeUntil(this.destory$)
            )
          .subscribe(() = > {
            console.log('End of navigation');
          });
      }
    
      ngOnDestroy(): void {
        this.destory$.next(true);
        this.destory$.unsubscribe(); }}Copy the code

    Don’t double subscribe

    What are the problems with the following code?

      / / select box
      select$ = new Subject();
      // Graph selection criteria
      chart$ = new Subject();
      // Table selection criteria
      table$ = new Subject();
    
      ngOnInit(): void {
        this.select$.subscribe(() = > {
          this.chart$.subscribe(this.getChartData())
          this.table$.subscribe(this.getTableData())
        })
      }
    Copy the code

    If it’s not clear, you can analyze the following code

    const child = document.querySelector('#child');
    document.addEventListener('click'.() = > {
      child.addEventListener('click'.() = > {
        console.log('Child is clicked');
      });
    });
    Copy the code


Copy the code