Задержка RxJS не менее X миллисекунд
Я пытаюсь реализовать следующее поведение в RxJS:
- Пожар события
- Вызов http API
- Когда API возвращается, либо:
- Подождите, пока не пройдет X миллисекунд с момента запуска события
- Немедленно возвращайтесь, если X миллисекунды уже прошли с момента запуска события
Это очень полезно для UX, потому что даже если вызов занимает 1 мс, я бы хотел показать значок загрузки не менее 100 мс.
Я не нашел способа реализовать это либо с delay
, throttle
, debounce
, либо с его вариантами.
this.eventThatFires
.switchMap(data => {
let startTime = Date.now();
return this.callHttpService(data)
.delay(new Date(startTime + 1000));
})
Я предположил, что что-то вроде этого сработало, но использование абсолютной даты, похоже, делает разницу во времени с текущим временем и не назначает задержку для этого абсолютного времени.
EDIT:
Кажется, нет встроенного оператора, который работает как то, что я описываю. Я просто создал его, потому что я буду использовать его во всем приложении:
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;
}
}
Ответы
Ответ 1
Эффективно delay
по дате совпадает с delay
по числу, единственное различие заключается в том, что продолжительность задержки вычисляется как разница в указанной дате и текущем времени.
Вы можете использовать оператор delayWhen
для вычисления задержки при испускании значения:
this.eventThatFires
.switchMap(data => {
let startTime = Date.now();
return this.callHttpService(data)
.delayWhen(() => Rx.Observable.timer(500 + startTime - Date.now()))
})
Ответ 2
Что не так с вашим решением combLatest?
Вы также можете использовать zip
:
this.eventThatFires
.switchMap(data => Observable.zip(
this.profileService.updateInfo(profileInfo)),
Observable.timer(500),
x => x));
Ответ 3
Богдан Савлук ответит с задержкой по функциональности
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 запроса (опрос не реже, чем каждые x секунд)
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()
Смотрите: онлайн