Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

253
Views
Can this rxjs merge logic be simplified?

I have an observable (onAuthStateChanged) from the Firebase client that:

  1. emits null immediately if the user is not signed in, and
  2. emits null and then a user object a few moments later if the user is signed in.
const observable = new Observable((obs) => {
    return app.auth().onAuthStateChanged(
        obs.next,
        obs.error,
        obs.complete
    )
})

What I want is to:

  1. ignore any emitted null values for the first 1000ms of the app lifecycle (null coming after 1000ms is accepted)
  2. always emit user object regardless of what time it comes
  3. if no user object comes in the first 1000ms, then emit null at the 1000ms mark

Here is what I've done (and it seems to work). However, I'm reluctant to use this code as it doesn't seem that concise:

const o1 = observable.pipe(skipUntil(timer(1000)))

const o2 = observable.pipe(
    takeUntil(o1),
    filter((user) => user !== null)
)

const o3 = timer(1000).pipe(takeUntil(o2), mapTo(null))

merge(o1, o2, o3).subscribe({
    next: setUser,
    error: console.log,
    complete: () => console.log("error: obs completed, this shouldn't happen"),
})

Is there a way to do this without merge? I tried going through the docs but I'm quite lost.

Thanks for your help!

about 4 years ago · Juan Pablo Isaza
2 answers
Answer question

0

You could use concat instead of merge. Think of it as using the first source until it completes, then use the second source.

const nonNullUser = firebaseUser.pipe(
    filter(user => user !== null),
    takeUntil(timer(1000))
);

const user = concat(nonNullUser, firebaseUser);

user.subscribe(...);

I just realized that this solution will not explicitly perform step #3 "emit null at the 1000ms mark". I was thinking subscribing to firebaseUser would emit the latest value. But, I'm not sure if that's true for your scenario.

If not, we could easily achieve this by adding shareReplay like this:

const firebaseUser = observable.pipe(shareReplay(1));
about 4 years ago · Juan Pablo Isaza Report

0

While I liked the answer from @BizzyBob I was genuinely intrigued by these requirements that I wanted to see what other options were available. Here's what I produced:

const auth$ = observable.pipe(
    startWith(null)
)

const null$ = timer(1000).pipe(
    switchMap(_=>auth$)
)

const valid$ = auth$.pipe(
    filter(user=>!!user)
)

const user$ = race(null$, valid$);

We have our source auth$ observable which gets your Firebase data. However, startWith() will immediately emit null before any values coming from Firebase.

I declared two observables for null and non-null cases, null$ and valid$.

The null$ observable will subscribe to auth$ after 1000ms. When this happens it immediately emits null thanks to the startWith() operator.

The valid$ observable subscribes to auth$ immediately but only emits valid user data thanks to filter(). It won't emit startWith(null) because it is caught by the filter.

Last, we declare user$ by using the race() operator. This operator accepts a list of observables as its parameters. The first observable to emit a value wins and is the resulting subscription.

So in our race, valid$ has 1000ms to emit a valid user. If it doesn't, race() will subscribe to null$ resulting in the immediate null, and all future values coming from Firebase.

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!