Skip to content

Instantly share code, notes, and snippets.

@kosich
Created May 31, 2019 08:06
Show Gist options
  • Save kosich/f5e88f52f588e6a3c8f604b9488f7da3 to your computer and use it in GitHub Desktop.
Save kosich/f5e88f52f588e6a3c8f604b9488f7da3 to your computer and use it in GitHub Desktop.
Loading indication with a delay and anti-flickering in RxJS
const { rxObserver } = require('api/v0.3');
const { fromEvent, timer, combineLatest, merge, throwError, of } = require('rxjs');
const { timeout, share, catchError, mapTo, takeUntil, startWith, distinctUntilChanged, switchMap, map } = require('rxjs/operators');
const delayTime = 150;
const shouldError = false;
const result$ = makeARequest(delayTime, shouldError).pipe(
timeout(700), // 700ms timeout for the result to come
catchError(() => { // an error from the request or timeout will be handled here
return of({ error: 'Oops' });
}),
share()
);
const showLoadingIndicator$ = merge(
// ON in 1second
timer(100).pipe( mapTo(true), takeUntil(result$) ),
// OFF once we receive a result, yet at least in 200ms
combineLatest(result$, timer(200)).pipe( mapTo(false) )
)
.pipe(
startWith(false),
distinctUntilChanged()
);
const [success$, error$] = result$.partition(result=>result.msg);
success$
.pipe(map(({ msg }) => msg))
.subscribe(rxObserver());
error$
.pipe(map(({ error }) => error))
.subscribe(rxObserver());
showLoadingIndicator$
.pipe(map(isLoading => isLoading ? '⏳ ' : '🙌 ') )
.subscribe(rxObserver());
function makeARequest(delayTime, shouldError){
return timer(delayTime).pipe(switchMap(()=>{
return shouldError
? throwError('X')
: of({ msg: 'OK' });
}));
}