Weboldal keresés

Hogyan lehet korlátozni egy mousemove eseményt RxJs-ben Angular 2 + Typescript használatakor?


Az RxJs tanulási folyamatban vagyok. Angular2 rc3-at használok. A következő stream működik, de túl sok mousemove eseményt ad. Szeretném lassítani őket időzítéssel (throttling) vagy egy másik vezérlő stream használatával. Hogyan tudnám ezt megtenni?

Egérmozgás-stream korlátozás nélkül

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

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

Egyszerű megoldás: A throttling használatának valahogy így kellene kinéznie:

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

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

- ezt a sample() operátort innen vettem: http://reactivex.io/documentation/operators/sample.html

De ez nem működik Angular 2 - CLI projektben. Ez a hibát adja:

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

Úgy gondolom, egy másik, erőteljesebb módja ugyanezen eredmény elérésének a következő lehet: Nagyszerű lenne, ha a legfrissebb mousemove item-et egy másik streamből kapott elemek alapján küldhetnénk. Bármelyik stream - amit mi hoztunk létre..

Például:

Amikor új elemet kapunk (1, 2, 3..) a eachSecond$ Stream-ből (=a mi „Vezérlő Streamünk”), - továbbítjuk lefelé (a mouseMoveEachSecond$-be) - a legutóbb kapott elemet a mouseMove$ stream-ből.

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 hang egyszerű. Ezt különösen nehéznek találtam megvalósítani - amennyire tudom, ennek oka az, hogy a stream állapotát valahogyan meg kell osztani. Szükség van egy módra, hogy meg lehessen mondani, mi lett már elküldve..

A mouseMoveEachSecond$-ben az elemek egyenként, sorban jönnek. Vagy egy szám, vagy egy objektum. Tudnod kell:

  • Melyik volt az utolsó időpont elem, amikor új egér elem érkezett.
  • És melyik volt az utolsó egér elem, amikor új idő elem érkezett.

Ez lehetővé teszi számodra, hogy:

  • ne küldjön egér elemet lefelé, amikor az egér nem mozog a képernyőn.
  • Ne küldj egy mouse item-t downstream felé, amíg nincs új time item kibocsátva az eachSecond$áramból.

Ezt globális változók használatával lehet megtenni. De ez nem az RxJS módszere a dolgok elvégzésére.. Nem tudok olyan módot, amivel az utoljára elküldött elemet tárolni lehetne és a következő lépésben használni. A reduce operátor megtarthatja az állapotot: egy felszabadított elemtől a másikig, de hogyan tudnánk ezt a tulajdonságot használni, hogy ezt a viselkedést elérjük? Ezeket a stream-eket végtelennek kell tekinteni. Hmm... kellene lennie egyszerűbb módnak, hogy össze lehessen kombinálni ezt a 2 stream-et.. Lehet, hogy még korai.. Úgy érzem, az agyam nem akar Streams-ben gondolkodni :)

Tehát a 2 kérdés világosan megfogalmazódott:

  1. melyek azok a módok, ahogyan egy mousemove streamet korlátozni lehet Angular 2-ben?
  2. Használhatok egy másik streamet arra, hogy irányítsam, mikor engedem el a mousemove elemeket? Ha igen, ez a „Vezérlő stream” lehet bármilyen stream, vagy vannak korlátozások?

Nagyon köszönöm:)

Válasz #1

Olyan közel vagy! Ironikus módon a varázsoperátorod valóban a sample.

A régi mintavételi változat (RxJS4-ből) túlterhelt volt, és számot is elfogadhatott paraméterként. Az RxJS5-ben (ami az Angular2-vel érkezik) szét lett választva, így valójában két operátor létezik: sample és sampleTime. Az utóbbi az, amely időparamétert fogad, és az adott időablakban az utolsó eseményt adja ki, amikor kibocsát.

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

Az előbbi egy Observable-t vesz egyedüli argumentumaként, és minden alkalommal kibocsátja az utoljára kapott elemet, amikor a vezérlő Observable kibocsát.

azaz

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)); 

Válasz #2

mi a helyzet a throttleTime importálásával:

import { throttleTime } from 'rxjs/operators';

és aztán így használd:

mousemouve$.pipe(
      throttleTime(5000)
    )