How can I delay an observable only if it returns faster than the delay

Viewed 888

Take for example:

 this.http.get('/getdata').pipe(delay(2000))

I would like this request to take a minimum of 2s to complete, but not any longer than it takes for the request to complete.

In other words:

  1. if the request takes 1s to complete, I want the observable to complete in 2s.

  2. if the request takes 3s to complete, I want the observable to complete in 3s NOT 5s.

Is there some other pipe other than delay() that can achieve this that I don't know about or is there a way to build a custom pipe for this if necessary?

The use case is to show a loader, however if the request completes too fast it doesnt look good when the loader just "flashes" for a split second

2 Answers

To answer the question as asked, you could simply use combineLatest() to combine a timer(2000) observable and the request observable, then just ignore the result from the timer observable. It works because combineLatest waits until all observables have emitted at least one value before emitting one itself.

combineLatest(this.http.get('/getdata'), timer(2000), x => x)

Thanks to GregL, I updated this to just use a forkJoin. This will get the latest value of the streams. But if you want to check it on every emmission, you can replace forkJoin with combineLatest and that will work too. In my working example:

    this.ibanSubscription = forkJoin({
        iban: this.ibantobicService.getById(Iban),
        timer: timer(1000) //so now the ajax call will take at least 1 second 
        }
    ).pipe(
        map( (stream: any) => <BicModel>stream.iban),
        switchMap( (bic: BicModel) => of(this.processIbanData(bic))),
        catchError((error: any) => of(this.messageList.handleError(error))),
        finalize(() => this.loadIbanToBicFinalize())
   ).subscribe();
Related