RxJS油门行为;立即获得第一个价值

时间:2016-05-10 18:16:45

标签: javascript rxjs throttling

示例Plunkr:https://plnkr.co/edit/NZwb3ol8CbZFtSc6Q9zm?p=preview

我知道rxjs有这3种节流方法(5.0 beta.4):

auditTime()throttleTime()debounceTime()

我正在寻找的行为是默认情况下lodash在节流下执行的行为:

  • 1)立即给我第一个值!
  • 2)对连续值,保持给定延迟的值,然后发出最后出现的值
  • 3)当油门延迟到期时,返回状态(1)

理论上,这应该是:

inputObservable
  .do(() => cancelPreviousRequest())
  .throttleTime(500)
  .subscribe((value) => doNextRequest(value))

但是

  • throttleTime永远不会给我最后一个值,如果在节流超时中发出
  • debounceTime不会立即触发
  • auditTime不会立即触发

我可以组合使用任何rxjs方法来实现所描述的行为吗?

3 个答案:

答案 0 :(得分:8)

对于在2018年之后寻求此功能的任何人:此功能已于一年前添加,但由于某些原因,文档尚未更新。

RxJS commit

您可以简单地将配置对象传递给throttleTime。默认值为{ leading: true, trailing: false }。要实现此处讨论的行为,您只需将trailing设置为true{ leading: true, trailing: true }

答案 1 :(得分:3)

对于较旧的RxJ,我编写了一个concatLatest运算符,可以完成您想要的大部分操作。有了它,您可以使用以下代码获得限制行为:

const delay = Rx.Observable.empty().delay(500);
inputObservable
    .map(value => Rx.Observable.of(value).concat(delay))
    .concatLatest()
    .subscribe(...);

这是运营商。我尝试更新它以使用RxJS5:

Rx.Observable.prototype.concatLatest = function () {
    /// <summary>
    /// Concatenates an observable sequence of observable sequences, skipping sequences that arrive while the current sequence is being observed.
    /// If N new observables arrive while the current observable is being observed, the first N-1 new observables will be thrown
    /// away and only the Nth will be observed.
    /// </summary>
    /// <returns type="Rx.Observable"></returns>
    var source = this;

    return Rx.Observable.create(function (observer) {
        var latest,
            isStopped,
            isBusy,
            outerSubscription,
            innerSubscription,
            subscriptions = new Rx.Subscription(function () {
              if (outerSubscription) {
                outerSubscription.unsubscribe();
              }
              if (innerSubscription) {
                innerSubscription.unsubscribe();
              }
            }),
            onError = observer.error.bind(observer),
            onNext = observer.next.bind(observer),
            innerOnComplete = function () {
                var inner = latest;
                if (inner) {
                    latest = undefined;
                    if (innerSubscription) {
                      innerSubscription.unsubscribe();
                    }
                    innerSubscription = inner.subscribe(onNext, onError, innerOnComplete);
                }
                else {
                    isBusy = false;
                    if (isStopped) {
                        observer.complete();
                    }
                }
            };

        outerSubscription = source.subscribe(function (newInner) {
            if (isBusy) {
                latest = newInner;
            }
            else {
                isBusy = true;
                if (innerSubscription) {
                  innerSubscription.unsubscribe();
                }
                innerSubscription = newInner.subscribe(onNext, onError, innerOnComplete);
            }
        }, onError, function () {
            isStopped = true;
            if (!isBusy) {
                observer.complete();
            }
        });

        return subscriptions;
    });
};

这是一个更新的plunkr:https://plnkr.co/edit/DSVmSPRijJwj9msefjRi?p=preview

注意我已将您的lodash版本更新到最新版本。在lodash 4.7中,我重写了油门/去抖操作符来修复一些边缘案例错误。您使用的是4.6.1仍有一些错误,但我认为它们不会影响您的测试。

答案 2 :(得分:2)

我使用auditTime运算符并更改了2行以实现所需的行为。

新的plunker:https://plnkr.co/edit/4NkXsOeJOSrLUP9WEtp0?p=preview

原文:

的变化:

来自(auditTime):

protected _next(value: T): void {
  this.value = value;
  this.hasValue = true;
  if (!this.throttled) {
    this.add(this.throttled = this.scheduler.schedule(dispatchNext, this.duration, this));
  }
}

clearThrottle(): void {
  const { value, hasValue, throttled } = this;
  if (throttled) {
    this.remove(throttled);
    this.throttled = null;
    throttled.unsubscribe();
  }
  if (hasValue) {
    this.value = null;
    this.hasValue = false;
    this.destination.next(value);
  }
}

to(auditTimeImmediate):

protected _next(value: T): void {
    this.value = value;
    this.hasValue = true;
    if (!this.throttled) {
        // change 1:
        this.clearThrottle();
    }
}

clearThrottle(): void {
    const { value, hasValue, throttled } = this;
    if (throttled) {
        this.remove(throttled);
        this.throttled = null;
        throttled.unsubscribe();
    }
    if (hasValue) {
        this.value = null;
        this.hasValue = false;
        this.destination.next(value);
        // change 2:
        this.add(this.throttled = this.scheduler.schedule(dispatchNext, this.duration, this));
    }
}

所以我在值为next之后开始超时。

用法:

inputObservable
  .do(() => cancelPreviousRequest())
  .auditTimeImmediate(500)
  .subscribe((value) => doNextRequest(value))