Comment limiter la fréquence d'un événement mousemove dans RxJs lors de l'utilisation d'Angular 2 + Typescript ?


Je suis en train d'apprendre RxJs. J'utilise Angular2 rc3. Le flux suivant fonctionne, mais il me donne trop d'événements mousemove. Je veux les ralentir en utilisant time (limitation) ou un autre flux de contrôle. Comment puis-je faire cela ?

Flux de déplacement de souris sans limitation

const mouseMove$ = Observable.fromEvent<MouseEvent>(document, 'mousemove');

mouseMove$.subscribe( x => console.log(x)); // works great, many {mouse position object} 's

Solution simple : L'utilisation de la limitation devrait être quelque chose comme ceci :

const mouseMove$ = Observable.fromEvent<MouseEvent>(document, 'mousemove');
const latestMouseEventEvery1Second$ = mouseMove$.sample(1000);

latestMouseEventEvery1Second$.subscribe( x => console.log(x)); // error

- cet opérateur sample() que j'ai pris ici : http://reactivex.io/documentation/operators/sample.html

Mais cela ne fonctionne pas dans un projet Angular 2 - CLI. Cela me donne cette erreur :

***Argument of type 'number' is not assignable to parameter of type 'Observable<\any>'*** - notice i've put <\MouseEvent> when casting.

Une autre manière plus puissante d'obtenir le même résultat, je pense que cela peut être la suivante : Ce serait génial si nous pouvions envoyer le dernier mousemove item basé sur les éléments reçus d'un autre flux. N'importe quel flux - créé par nous..

Par exemple :

Lorsque nous recevons un nouvel élément (1, 2, 3..) du flux eachSecond$ (=notre « flux de contrôle »), nous émettons en aval (dans le mouseMoveEachSecond$) le dernier élément reçu du flux mouseMove$.

const eachSecond$ = Observable.timer(0, 1000); // starts at 0 and gives 1,2,3 as values each 1000 milliseconds.
const mouseMove$ = Observable.fromEvent<MouseEvent>(document, 'mousemove');

const mouseMoveEachSecond$ = Observable.merge(eachSecond$,mouseMove$)
  .some magic operator I can't find()
  // this could work like this:
    // many mouse items are coming at a high rate from the mouse stream
    // only a few items (1,2,3..) are coming form the eachSecond$ stream
    //the logic: We send downstream **only one mouse item** (the last) for each new item that is coming form the eachSecond$ stream.
);

mouseMoveEachSecond$.subscribe( x => console.log(x)); 
// a { mouse position object } = mouse item - only when you move the mouse 
// and no more than one {mouse position object} per second}

Ça semble simple. J'ai trouvé cela particulièrement difficile à mettre en œuvre - d'après ce que je peux dire, c'est parce que l'état du flux devrait être partagé d'une manière ou d'une autre. Une manière de savoir ce qui a déjà été envoyé est nécessaire..

Dans le mouseMoveEachSecond$, les éléments arrivent un par un, dans l'ordre. Ou un nombre ou un objet. Vous devez savoir :

  • Quel a été le dernier élément de temps lorsque vous avez reçu un nouveau élément de souris.
  • Et quel était le dernier élément de souris lorsque vous recevez un nouvel élément de temps.

Cela vous permettra de :

  • ne pas envoyer un élément souris en aval lorsque la souris ne bouge pas à l’écran.
  • ne pas envoyer un élément souris en aval tant qu'aucun nouveau élément temps n'est libéré depuis le flux eachSecond$.

Cela peut être fait en utilisant des variables globales. Mais ce n'est pas la façon de faire avec RxJS. Je ne connais pas de moyen pour stocker le dernier élément envoyé et l'utiliser à l'étape suivante. L'opérateur reduce peut conserver l'état : d'un élément libéré à un autre, mais comment pouvons-nous utiliser cette propriété pour obtenir ce comportement ? Ces flux doivent être considérés comme infinis. Hmm... il devrait y avoir une façon plus simple de combiner ces deux flux... Peut-être que c'est trop tôt... J'ai l'impression que mon cerveau ne veut pas penser en flux :)

Donc les 2 questions sont clairement posées :

  1. quelles sont quelques façons de limiter un flux mousemove dans Angular 2 ?
  2. Puis-je utiliser un autre flux pour contrôler quand je libère les éléments mousemove ? Si oui, ce « flux de contrôle » peut-il être n’importe quel flux, ou y a-t-il des limitations ?

Merci beaucoup :)

Réponse #1

Tu es si proche ! Ironiquement, ton opérateur magique est sample.

L'ancienne variante de sample (de RxJS4) était surchargée et pouvait prendre un nombre comme argument. Dans RxJS5 (celle fournie avec Angular2), elle a été séparée de sorte qu'il y ait en réalité deux opérateurs sample et sampleTime. Ce dernier est celui qui prend un argument de temps et prend le dernier événement dans une fenêtre temporelle donnée lorsqu'il émet.

const mouseMoveEachSecond$ = mouseMove$.sampleTime(1000);

Le premier prend un Observable comme seul argument et émet le dernier élément reçu chaque fois que le Observable de contrôle émet.

c.-à-d.

const eachSecond$ = Observable.timer(0, 1000); // starts at 0 and gives 1,2,3 as values each 1000 milliseconds.
const mouseMove$ = Observable.fromEvent<MouseEvent>(document, 'mousemove');

const mouseMoveEachSecond$ = mouseMove$.sample(eachSecond$);

mouseMoveEachSecond$.subscribe( x => console.log(x)); 

Réponse #2

qu'en est-il de l'importation de throttleTime :

import { throttleTime } from 'rxjs/operators';

et ensuite l'utiliser comme tel :

mousemouve$.pipe(
      throttleTime(5000)
    )