Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What may happen if you don't unsubscribe from an Observable in canActivate of a guard?

Tags:

angular

rxjs

Please, see an example below

import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from '@angular/router';
import {Observable, of} from 'rxjs';
import {Injectable} from '@angular/core';
import {AuthService} from './auth.service';
import {map, take} from 'rxjs/operators';

@Injectable({providedIn: 'root'})
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService,
              private router: Router) {
  }
  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> | Observable<boolean | UrlTree> | boolean {
    return this.authService.user.pipe(
      take(1),
      map(user => {
        if (!!user) {
          return true;
        }
        return this.router.createUrlTree(['/auth']);
      }));
  }
}

The user is of type BehaviorSubject, and it defines an authorization status of an user, that is if it is equal to an object, then an user is logged in, and not otherwise. Therefore, the guard activates /auth route if the user is logged in, and it redirects us otherwise. Now, what will happen if I remove take(1) from the pipeline so that we do not unsubscribe as a result?

like image 335
alexander.sivak Avatar asked Nov 15 '25 21:11

alexander.sivak


2 Answers

Nothing will happen, the same behaviour you experience will be preserved. I guess this question is angled more towards the "cost" of not unsubscribing.

Under the hood, angular adds the first operator to the observable, which completes the observable after emitting the first value.

This was added on this PR

like image 158
C_Ogoo Avatar answered Nov 17 '25 10:11

C_Ogoo


I think there is nothing to worry about. As far as I can see, every time a canActivate guard is run, by using first(), it will automatically unsubscribe from the returned observable.

check_guard.ts

function runCanActivate(
    futureRSS: RouterStateSnapshot, futureARS: ActivatedRouteSnapshot,
    moduleInjector: Injector): Observable<boolean|UrlTree> {
  const canActivate = futureARS.routeConfig ? futureARS.routeConfig.canActivate : null;
  if (!canActivate || canActivate.length === 0) return of (true);

  const canActivateObservables = canActivate.map((c: any) => {
    return defer(() => {
      const guard = getToken(c, futureARS, moduleInjector);
      let observable;
      if (isCanActivate(guard)) {
        observable = wrapIntoObservable(guard.canActivate(futureARS, futureRSS));
      } else if (isFunction<CanActivateFn>(guard)) {
        observable = wrapIntoObservable(guard(futureARS, futureRSS));
      } else {
        throw new Error('Invalid CanActivate guard');
      }
      return observable.pipe(first()); // <----------- Here!
    });
  });
  return of (canActivateObservables).pipe(prioritizedGuardValue());
}
like image 23
Andrei Gătej Avatar answered Nov 17 '25 11:11

Andrei Gătej



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!