RxJS延迟至少X毫秒

时间:2017-04-07 18:07:26

标签: typescript rxjs

我正在尝试在RxJS中实现以下行为:

  1. 点火活动
  2. 调用http API
  3. 当API返回时,或者:
    1. 等待自触发事件至少经过X毫秒
    2. 如果自触发事件以来已经过了X毫秒,则立即返回
  4. 这对用户体验非常有用,因为即使呼叫需要1毫秒,我也想显示至少100毫秒的加载图标。

    我没有找到任何方法来实现此问题,包括delaythrottledebounce或其变体。

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

    我认为这样的事情有效,但是使用绝对日期似乎与当前时间有所不同,并且没有安排该绝对时间的延迟。

    编辑:

    似乎没有内置的运算符可以像我描述的那样工作。我刚创建它是因为我将在整个应用程序中大量使用它:

    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;
        }
    }
    

4 个答案:

答案 0 :(得分:5)

按日期有效delaydelay按编号相同,唯一的区别是延迟时间计算为指定日期和当前时间的差异。

您可以使用delayWhen运算符计算发出值时的延迟:

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

答案 1 :(得分:2)

您的combineLatest解决方案有什么问题?

您还可以使用zip

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

答案 2 :(得分:1)

我根据Martin的最终解决方案制作了一个自定义rxjs运算符。

import { combineLatest, Observable, OperatorFunction, timer } from "rxjs";
import { map } from "rxjs/operators";

export function delayAtLeast<T>(delay: number): OperatorFunction<T, T> {
  return function(source$: Observable<T>): Observable<T> {
    return combineLatest([timer(delay), source$]).pipe(map(x => x[1]));
  }
}

答案 3 :(得分:0)

基于Bogdan Savluk的答案。延迟功能已解耦:

sbt run

http请求的情况(至少每x秒轮询一次)

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)))

请参阅:online