Tengo un observable (onAuthStateChanged) del cliente de Firebase que:
null inmediatamente si el usuario no ha iniciado sesión, ynull y luego un user object unos momentos más tarde si el usuario ha iniciado sesión. const observable = new Observable((obs) => { return app.auth().onAuthStateChanged( obs.next, obs.error, obs.complete ) })Lo que quiero es:
null emitido durante los primeros 1000 ms del ciclo de vida de la aplicación (se acepta el valor null que viene después de 1000 ms)user object independientemente de la hora a la que llegueuser object en los primeros 1000 ms, emita un null en la marca de 1000 msEsto es lo que he hecho (y parece funcionar). Sin embargo, soy reacio a usar este código ya que no parece tan conciso:
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"), })¿Hay alguna manera de hacer esto sin fusionar? Intenté revisar los documentos pero estoy bastante perdido.
¡Gracias por tu ayuda!
Podrías usar concat en lugar de fusionar. Piense en ello como si usara la primera fuente hasta que se complete, luego use la segunda fuente.
const nonNullUser = firebaseUser.pipe( filter(user => user !== null), takeUntil(timer(1000)) ); const user = concat(nonNullUser, firebaseUser); user.subscribe(...); Me acabo de dar cuenta de que esta solución no realizará explícitamente el paso n. ° 3 " emitir nulo en la marca de 1000 ms ". Estaba pensando que suscribirme a firebaseUser emitiría el valor más reciente. Pero, no estoy seguro si eso es cierto para su escenario.
Si no, podríamos lograrlo fácilmente agregando shareReplay de esta manera:
const firebaseUser = observable.pipe(shareReplay(1));Si bien me gustó la respuesta de @BizzyBob, estaba realmente intrigado por estos requisitos y quería ver qué otras opciones estaban disponibles. Esto es lo que produje:
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$); Tenemos nuestra fuente auth$ observable que obtiene sus datos de Firebase. Sin embargo, startWith() emitirá inmediatamente un valor null antes de cualquier valor proveniente de Firebase.
Declaré dos observables para casos nulos y no nulos, null$ y valid$ .
El observable null$ se suscribirá a auth$ después de 1000 ms. Cuando esto sucede, inmediatamente emite un null gracias al operador startWith() .
El observable valid$ se suscribe a auth$ inmediatamente pero solo emite datos de usuario válidos gracias a filter() . No emitirá startWith(null) porque el filtro lo atrapa.
Por último, declaramos user$ usando el operador race() . Este operador acepta una lista de observables como sus parámetros. El primer observable en emitir un valor gana y es la suscripción resultante.
Entonces, en nuestra carrera, valid$ tiene 1000 ms para emitir un usuario válido. Si no es así, race() se suscribirá a null$ , lo que dará como resultado el null inmediato y todos los valores futuros provenientes de Firebase.