web-dev-qa-db-fra.com

Rebond immédiat en Rx

Je recherche un opérateur pour debounce une série d'événements, disons le clic de l'utilisateur. L'entrée et la sortie doivent être comme ceci:

interval :      ->     <-            ->     <-
in       : 1--2--3-------4--5--5--6-7-8--------
out      : 1-------------4---------------------

L'idée est comme le rebond du soulignement avec immediate option onhttp://underscorejs.org/#debounce . L'opérateur peut être présenté/implémenté dans n'importe quel langage prenant en charge les extensions réactives

Edit: Clarifiez l'intervalle, disons 5 secondes (5 espaces entre deux flèches): -> <-

Edit2: Une version plus compréhensible: j'ai un utilisateur, il clique à plusieurs reprises sur un bouton (1, 2, 3); Je veux attraper le premier click (1) et ignorer le reste. Après un certain temps, il est fatigué et se repose pendant 7 secondes (ce qui est plus long que l'intervalle de 5 secondes entre deux flèches) et continue de cliquer à nouveau sur le bouton (4, 5, 6, 7, 8) Je veux attraper le premier click (4) et ignorez le reste.

S'il clique après la quatrième flèche, je veux aussi attraper ce clic.

Edit3: Voici une image image qui peut être trouvé sur le article d'origine

17
Quang Linh Le

Edit: D'après les clarifications, RxJava n'a pas d'opérateur pour ce type de flux mais il peut être composé d'un ensemble non trivial d'autres opérateurs:

import Java.util.concurrent.TimeUnit;

import rx.Observable;

public class DebounceFirst {

    public static void main(String[] args) {
        Observable.just(0, 100, 200, 1500, 1600, 1800, 2000, 10000)
        .flatMap(v -> Observable.timer(v, TimeUnit.MILLISECONDS).map(w -> v))
        .doOnNext(v -> System.out.println("T=" + v))
        .compose(debounceFirst(500, TimeUnit.MILLISECONDS))
        .toBlocking()
        .subscribe(v -> System.out.println("Debounced: " + v));
    }

    static <T> Observable.Transformer<T, T> debounceFirst(long timeout, TimeUnit unit) {
        return f -> 
            f.publish(g ->
                g.take(1)
                .concatWith(
                    g.switchMap(u -> Observable.timer(timeout, unit).map(w -> u))
                    .take(1)
                    .ignoreElements()
                )
                .repeatWhen(h -> h.takeUntil(g.ignoreElements()))
            );
    }
}
14
akarnokd

Le comportement souhaité n'est pas celui de l'opérateur debounce dans Rx.

Cela s'appelle throttle, throttleTime ou throttleWithTimeout (cependant, il appartient à la catégorie d'opérateurs debounce). Je ne sais pas quelle langue vous utilisez mais dans RxJS, cela ressemble à l'image suivante:

enter image description here

Voir http://reactivex.io/documentation/operators/debounce.html .

9
martin

Étant donné que debounce() est intrinsèquement asynchrone, vous devez ramener le résultat au thread actuel de manière explicite.

seriesOfUnfortunateEvents
  .debounce( 14, TimeUnit.MILLISECONDS )
  .observeOn( Schedulers.immediate() )
  .subscribe( v -> yourStuff() );
1
Bob Dalgleish

Selon documentation il y a deux opérateurs anti-rebond dans RxJS. Vous pourriez être intéressé par debounceTime en particulier.

debounceTime

À partir de la documentation

N'émet une valeur de la source Observable qu'après un laps de temps donné sans autre émission de source.

Exemple:

Rx.Observable
    .fromEvent(document.querySelector('button'), 'click')
    .debounceTime(200)
    .mapTo(() => 'clicked!')
    .subscribe(v => console.log(v));

Il en émettra un cliqué ! si le bouton a été cliqué dans un intervalle de temps donné (200 ms dans cet exemple).

debounce

À partir de la documentation

N'émet une valeur de la source observable qu'après un laps de temps particulier déterminé par un autre observable s'est écoulé sans autre émission de la source.

1
Michał Pietraszko