RxJS:定期采样去抖动

时间:2017-08-20 01:31:01

标签: javascript rxjs

我有Observable从用户输入发出值的流(滑块的偏移值)。

我想去抖那个流,所以当用户忙着滑动时,我只会发出一个值,如果没有任何东西,比如说100毫秒,以避免被值淹没。但是,如果它只是无休止地去抖动(用户来回连续滑动),我还想每1秒发出一个值。一旦用户停止滑动,我只想要去抖动流中的最终值。

所以我想将debounce与流的常规“采样”结合起来。现在我的设置是这样的:

const debounce$ = slider$.debounceTime(100),
      sampler$ = slider$.auditTime(1000);

debounce$
    .merge(sampler$)
    .subscribe((value) => console.log(value));

假设用户将滑块移动2.4秒,则会发出如下值:

 start                      end
  (x)---------|---------|---(x)|----|
              |         |      |    |
             1.0       2.0    2.5  3.0  <-- unwanted value at the end
              ^         ^      ^
            sample   sample   debounce  <-- these are all good

我不希望在3秒时发出额外的值(来自sampler$流)。

显然merge是组合这两个流的错误方法,但我无法弄清楚切换种族的组合窗口或此处可以使用的任何内容。

2 个答案:

答案 0 :(得分:2)

您可以通过编写用作信号的observable来解决问题,指示用户当前是否正在滑动。这应该这样做:

const sliding$ = slider$.mapTo(true).merge(debounce$.mapTo(false));

您可以使用它来控制sampler$是否发出值。

一个工作示例:

&#13;
&#13;
const since = Date.now();
const slider$ = new Rx.Subject();

const debounce$ = slider$.debounceTime(100);
const sliding$ = slider$.mapTo(true).merge(debounce$.mapTo(false));

const sampler$ = slider$
  .auditTime(1000)
  .withLatestFrom(sliding$)
  .filter(([value, sliding]) => sliding)
  .map(([value]) => value);

debounce$
  .merge(sampler$)
  .subscribe(value => console.log(`${time()}: ${value}`));

// Simulate sliding:

let value = 0;
for (let i = 0; i <= 2400; i += 10) {
  value += Math.random() > 0.5 ? 1 : -1;
  slide(value, i);
}

function slide(value, at) {
  setTimeout(() => slider$.next(value), at);
}

function time() {
  return `T+${((Date.now() - since) / 1000).toFixed(3)}`;
}
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:2)

对于那些感兴趣的人,这是我采用的方法,受到@cartant's answer的启发。

const slider$ = new Rx.Subject();
const nothing$ = Rx.Observable.never();

const debounce$ = slider$.debounceTime(100);
const sliding$ = slider$.mapTo(true)
  .merge(debounce$.mapTo(false))
  .distinctUntilChanged();

const sampler$ = sliding$
  .switchMap((active) => active ? slider$.auditTime(1000) : nothing$);

debounce$
  .merge(sampler$)
  .subscribe(value => console.log(`${time()}: ${value}`));

不同之处在于在distinctUntilChanged流上添加sliding$以仅获取开/关更改,然后在其上执行switchMap以使得采样器返回值。