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;
}
}
source to share
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()))
})
source to share
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
source to share