RxJS сначала возьмите, затем дроссель и подождите

Я хочу наблюдать за событием mousewheel с помощью RxJS-DOM, чтобы, когда срабатывает первое событие, я пересылаю его, а затем отбрасываю все значения до тех пор, пока задержка между последующими значениями не пройдет ранее заданную продолжительность.

Оператор, который я представляю, может выглядеть примерно так:

Rx.DOM.fromEvent(window, 'mousewheel', (e) => e.deltaY)
.timegate(500 /* ms */)

Представьте себе следующий поток данных:

0 - (200 ms) - 1 - (400ms) - 2 - (600ms) - 3

где отправляемое значение - это число, а время описывает, сколько времени потребуется для получения следующего значения. Поскольку 0 является первым значением, оно будет выдано, а затем все значения до 3 будут отброшены, потому что отдельные задержки между последующими значениями не превышают 500ms.

В отличие от дроссельной заслонки, временная задержка между значениями вычисляется независимо от того, было ли выпущено последнее полученное значение или нет. С дроссельной заслонкой будет отправлено 0, пройдет 200 мс, 1 будет оценено и завершится ошибкой, пройдет 400 мс, а 2 будет оценено и ПРОЙДЕН, потому что время между последним выданным значением (0) и текущим полученным (2 ) составляет 600 мс, тогда как с моим оператором он будет оцениваться относительно 1, а время будет составлять 400 мс, поэтому тест не пройден.

И этот оператор тоже не дребезжит. Вместо того, чтобы ждать, пока истечет интервал для выдачи, он сначала отправляет первое значение, затем сравнивается со всеми будущими значениями и так далее.

Такой оператор уже существует? А если нет, как бы я его сделал?


person barndog    schedule 19.05.2016    source источник
comment
comment
Нет, debounce отправляет значение ПОСЛЕ временного интервала, я хочу, чтобы значение было отправлено раньше, а затем отбрасывать все значения, которые не превышают продолжительность после отправки первого значения.   -  person barndog    schedule 20.05.2016
comment
Из документации: испускает элемент из источника Observable по истечении определенного промежутка времени, при этом Observable не пропускает какие-либо другие элементы. --ИЛИ-- Игнорирует значения из наблюдаемой последовательности, за которыми следует другое значение в пределах вычисленной длительности устранения дребезга.   -  person barndog    schedule 20.05.2016
comment
Таким образом, debounce получит значение, дождется истечения продолжительности, затем пересылает это значение и, в противном случае, отбрасывает его ИЛИ проигнорирует значение, которое имеет значения, отправленные после него, после вычисленной продолжительности. Я не хочу игнорировать это значение, я хочу отправить это первое значение и пропустить все остальные, у которых нет интервала между nth-1 и nth.   -  person barndog    schedule 20.05.2016
comment
@ go-oleg в примере, который я привел, с использованием debounce, 0 никогда не будет отправлен, только 2 будет, потому что задержка между 2 и 3 больше, чем предоставленный интервал в 500 мс.   -  person barndog    schedule 20.05.2016
comment
Ах я вижу. throttle больше похож на это тогда.   -  person go-oleg    schedule 20.05.2016
comment
Это тоже не дроссель.   -  person barndog    schedule 20.05.2016
comment
Дроссель отправит первое значение во временном интервале, затем дождется следующего временного интервала и отправит первое полученное значение и так далее. Итак, в моем примере потока использование throttle приведет к выходу 0, 2, 3, а не 0 3, потому что throttle смотрит на накопленную разницу во времени от последнего выданного значения до текущего значения.   -  person barndog    schedule 20.05.2016
comment
Так, например, при использовании дроссельной заслонки 0 будет отправлено, затем пройдет 200 мс, 1 будет оценено и завершится ошибкой, затем пройдет 400 мс, а 2 будет оценено и пройдет, потому что продолжительность между последним выданным значением (0) и 2 составляет 600 мс, что является ›= 500 мс. То, что я описываю, должно оценивать время, прошедшее с момента последнего полученного значения, а не последнего выданного значения, если это имеет смысл. Я уточню в своем посте.   -  person barndog    schedule 20.05.2016
comment
взгляните на stackoverflow.com/questions/37146081/   -  person user3743222    schedule 20.05.2016
comment
Я должен был указать, я использую github.com/Reactive-Extensions/RxJS, а не github.com/ReactiveX/rxjs, потому что я не собираюсь интегрировать бета-библиотеку в свой производственный код.   -  person barndog    schedule 20.05.2016


Ответы (2)


Вы можете относительно легко добиться этого, используя оператор timeInterval, который точно вычисляет временной интервал между последовательными значениями. Вот пример кода, который вы можете адаптировать под свой облик.

http://jsfiddle.net/a7uusL6t/

var Xms = 500;
var click$ = Rx.Observable.fromEvent(document, 'click').timeInterval()
var firstClick$ = click$.first().map(function(x){return x.value});

var res$ = firstClick$
  .concat(click$
    .filter(function (x) {
      console.log('interval', x.interval);
      return x.interval > Xms;})
    .map(function(x){return x.value})
   );

res$.subscribe(function(x){console.log(x)})
person user3743222    schedule 20.05.2016

Я решил свою проблему чем-то похожим, но более изысканным, чем ответ @ user3743222:

const events = Rx.Observable.fromEvent(window, 'mousewheel', (e) => e.deltaY);
const firstEventObservable = events.take(1);
const remainingEventsObservable = events.skip(1)
    .timeInterval()
    .filter(x => x.interval >= this.props.delayDuration)
    .map(x => x.value);
const pageChangeObservable = firstEventObservable.concat(remainingEventsObservable);
person barndog    schedule 20.05.2016
comment
более изысканный в каком смысле? Я не вижу такой большой разницы. Мне не нужно использовать skip, поскольку concat это уже делает. Кроме того, это все равно - person user3743222; 20.05.2016