RxJS 限制相同的值但让新值通过

erh*_*ise 6 throttling operators rxjs

“给你”,有人说,你得到了这个输入的值流,你有点想对它做 distinctUntilChanged() ......

Input:  '1-1----11---2--1122----1---2---2-2-1-2---|'
Output: '1-----------2--1-2-----1---2-------1-2---|'
Run Code Online (Sandbox Code Playgroud)

到目前为止没有什么奇怪的,
但是现在有人说如果相同的值再次出现“没关系”,“但前提是不会很快!”。我希望至少'----'在相同的值之间有刻度。“Okey”你说,你加了一个油门

const source = new Subject<number>();

// mysterious cave troll is randomly source.next(oneOrTwo)

const example = source.pipe(throttle(val => interval(4000)));

Input:  '1-1----11---2--1122----1---2---2-2-1-2-----|'
Output: '1------1----2----2-----1-------2-----2-----|'
Run Code Online (Sandbox Code Playgroud)

“这不是我想要的!看看你错过的所有价值”,指的是你对所有正在传输的价值进行节流。

Input:  '1-1----11---2--1122----1---2---2-2-1-2-----|'
Output: '1------1----2----2-----1-------2-----2-----|'
        '-------------->1<--------->2<----->1<------|' <-- Missed values
Run Code Online (Sandbox Code Playgroud)

“来,让我给你看看”神秘人说,并给了你这个

想要的输出

Input:  '1-1----11---2--1112----1---2---2-2-1-2-----|'
Output: '1------1----2--1--2----1---2-----2-1-------|'
Run Code Online (Sandbox Code Playgroud)

我对此的回答是,感觉组合窗口行不通。

从更有经验的人
那里这是一个很难解决的问题吗?(或者我错过了一个明显的解决方案)

Gog*_*eli 5

首先,我想出了以某种方式组合distinctUntilChanged()and 的想法throttleTimte(),但是我无法想出解决方案,然后我尝试了其他方法。

我想出的运算符throttleDistinct()可以按照您的意愿工作:StackBlit Editor Link

它有2个参数,分别是:

  1. duration: number 以毫秒为单位,类似于持续时间 throttleTime(duration: number)
  2. equals: (a: T, b: T) => boolean 这是比较前一项是否等于下一项的函数,默认实现为 (a, b) => a === b

import { of, fromEvent, interval, Observable } from 'rxjs';
import { map, scan, filter, } from 'rxjs/operators';

const source = fromEvent(document, 'keypress')
  .pipe(map((x: any) => x.keyCode as number))

source
  .pipe(
    throttleDistinct(1000),
  )
  .subscribe((x) => console.log('__subscribe__', x));

export function throttleDistinct<T>(
  duration: number,
  equals: (a: T, b: T) => boolean = (a, b) => a === b
) {
  return (source: Observable<T>) => {
    return source
      .pipe(
        map((x) => {
          const obj = { val: x, time: Date.now(), keep: true };
          return obj;
        }),
        scan((acc, cur) => {
          const diff = cur.time - acc.time;

          const isSame = equals(acc.val, cur.val)
          return diff > duration || (diff < duration && !isSame)
            ? { ...cur, keep: true }
            : { ...acc, keep: false };
        }),
        filter((x) => x.keep),
        map((x) => x.val),
      )
  }
}
Run Code Online (Sandbox Code Playgroud)


erh*_*ise 0

我找到了一个可行的解决方案,有人对此有什么看法吗?

source.pipe(
   windowTime(4000),
   concatMap(obs => obs.pipe(distinct()))
);
Run Code Online (Sandbox Code Playgroud)

之前的示例,在StackBlitz 示例中

更新:这实际上并不能 100% 工作。它只考虑当前窗口。所以你可以例如

`[1-12][2---]` which would give `1--22---|`
Run Code Online (Sandbox Code Playgroud)

其中[----]代表时间窗口。换句话说,如果一个值首先在一个窗口中最后发出,并在下一个窗口中首先发出,则相同的值将紧接着彼此通过。

感谢@eric99 让我意识到这一点。