RxJS latency at least X milliseconds

I am trying to implement the following behavior in RxJS:

  • Fire event
  • HTTP API call
  • When the API returns, either:
    • Wait until X milliseconds have passed since the event was fired
    • Return immediately if X milliseconds have already passed since the event was fired

This is very useful for UX because even if the call takes 1ms, I would like to show the loading icon at least 100ms.

I have not found a way to realize it either delay

, throttle

, debounce

or its variants.

this.eventThatFires
    .switchMap(data => {
        let startTime = Date.now();
        return this.callHttpService(data)
            .delay(new Date(startTime + 1000));
    })

      

I assumed that something like this worked, but using an absolute date seems to make a time difference to the current time and does not assign a delay to that absolute time.


EDIT:

There seems to be no built-in operator that works like what I am describing. I just created it because I will be using it throughout my application:

import { Observable } from "rxjs/Observable";

function delayAtLeast<T>(this: Observable<T>, delay: number): Observable<T> {
    return Observable.combineLatest(
        Observable.timer(delay),
        this)
    .map(([_, i]) => i);
}

Observable.prototype.delayAtLeast = delayAtLeast;

declare module "rxjs/Observable" {
    interface Observable<T> {
        delayAtLeast: typeof delayAtLeast;
    }
}

      

+11


source to share


3 answers


Effectively delay

by date is the same as delay

by number, the only difference is that the delay duration is calculated as the difference between the specified date and the current time.

You can use the operator delayWhen

to calculate the delay when the value is emitted:



this.eventThatFires
    .switchMap(data => {
        let startTime = Date.now();
        return this.callHttpService(data)
            .delayWhen(() => Rx.Observable.timer(500 + startTime - Date.now()))
    })

      

+6


source


What's wrong with your combLatest solution?

You can also use zip

:



this.eventThatFires
    .switchMap(data => Observable.zip(
        this.profileService.updateInfo(profileInfo)),
        Observable.timer(500),
        x => x));

      

+2


source


Bogdan Savluk will respond with a delay in functionality

let effectiveDelay=(delay)=>{
    let effectiveTimer = (now=>delay=>timer(delay+now - Date.now() )) (Date.now())
    return delayWhen(()=>effectiveTimer(delay));
}


this.eventThatFires
    .switchMap(data => this.callHttpService(data)
                .pipe(effectiveDelay(500)))

      

Http request case (poll at least every x seconds)

import { of, timer } from 'rxjs';
import { ajax } from 'rxjs/ajax';
import { delayWhen, switchMap, tap, repeat, map } from 'rxjs/operators';

const display = text => {
    console.log(new Date(), text);
};

let effectiveDelay=(delay)=>{
    let effectiveTimer = (now=>delay=>timer(delay+now - Date.now() )) (Date.now())
    return delayWhen(()=>effectiveTimer(delay));
}

of({}).pipe(
    switchMap(data => {
        return ajax({url:"https://httpbin.org/delay/2", crossDomain:true}).pipe(effectiveDelay(1000), map(ax=>ax.response) )
    }), tap(display), repeat())
  .subscribe()

      

Watch: online

0


source







All Articles