Skip to main content
3 of 4
Added input parameter to make it clear
andras
  • 212
  • 1
  • 6

How to (or should I) refactor RxJS nested subscriptions with intermediate return value?

I hope this fits more here than SO because it is mostly about code design than making it work. Also, this is not tied to RxJs, but more to the reactive paradigm. (TypeScript tag is only added to make the code highlighted.)

So this is what the code looks like, though this is just an overview. Actual function names are different than in the real world:

// Returns true if successfully tried to login
public tryLogin(userId: number): Observable<boolean> {
    const result = new ReplaySubject<boolean>();

    this.checkIfUserIsAuthorizedFromDatabase()
        .subscribe(
            user =>{
                if(user.id === userId) {
                    result.next(true);
                    result.complete();
                    return;
                }
    
                this.checkIfUserHasAccess(user)
                    .subscribe(
                        access => {
                            if(access.banned) {
                                result.next(false);
                                result.complete();
                                return;
                            }
                            // ... many other nestings and function calls
                            
                            // Watch the result passed in
                            this.checkLastWorkingLogin(user, result);
                        },
                        error => {
                            result.error(error)
                            // Sidenote: No idea why complete is called
                            result.complete()   
                        }
                    )
            },
            error => result.error(error));

    return result;
}

Problems with the current setup:

  • a result object is passed around into functions, rather than the function to return a true/false Observable
  • the deeply nested code makes it hard to read
  • since there is no single observable chain, the code is incredibly difficult to debug (can not use tap at a single place)
  • Observables are used as an ES5 Promise, but they are much more than that

Observables would be needed to be connected somehow by flatMap, but the chain should be finished up once the login process is terminally decided.

(Caching the single output is not a problem, observable will be simply cached.)

So can this code actually be refactored into something more readable that is more authentic to the libraries it is currently using?

Any suggestion is appreciated.

andras
  • 212
  • 1
  • 6