Hvordan begrense et mousemove-hendelse i RxJs når man bruker Angular 2 + Typescript?
Jeg er i ferd med å lære RxJs. Jeg bruker Angular2 rc3. Den følgende strømmen fungerer, men den gir meg for mange mousemove-hendelser. Jeg vil bremse dem ned ved å bruke tid (throttling) eller en annen kontrollstrøm. Hvordan kan jeg gjøre det?
Musbevegelsesstrøm uten struping
const mouseMove$ = Observable.fromEvent<MouseEvent>(document, 'mousemove');
mouseMove$.subscribe( x => console.log(x)); // works great, many {mouse position object} 's
Enkel løsning: Å bruke throttling bør være noe slikt som dette:
const mouseMove$ = Observable.fromEvent<MouseEvent>(document, 'mousemove');
const latestMouseEventEvery1Second$ = mouseMove$.sample(1000);
latestMouseEventEvery1Second$.subscribe( x => console.log(x)); // error
- denne sample() operatoren jeg har tatt fra her: http://reactivex.io/documentation/operators/sample.html
Men dette fungerer ikke i Angular 2 - CLI-prosjekt. Gir meg denne feilen:
***Argument of type 'number' is not assignable to parameter of type 'Observable<\any>'*** - notice i've put <\MouseEvent> when casting.
En annen mer kraftfull måte å oppnå samme resultat på, tror jeg kan være følgende: Det ville være flott om vi kunne sende den siste mousemove item basert på elementene mottatt fra en annen strøm. Enhver strøm - opprettet av oss..
For eksempel:
Når vi mottar et nytt element (1, 2, 3..) fra eachSecond$ Strøm (=vår "Kontrollstrøm"), - sender vi nedstrøms (inn i mouseMoveEachSecond$) - det siste elementet mottatt fra mouseMove$ strømmen.
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}
Lyd er enkelt. Jeg syntes dette var spesielt vanskelig å implementere - så vidt jeg kan forstå, skyldes dette at tilstanden til strømmen bør deles på en eller annen måte. En måte å vite hva som allerede er sendt på er nødvendig..
I mouseMoveEachSecond$kommer elementene ett etter ett, i rekkefølge. Eller et tall eller et objekt. Du må vite:
- Hva var det siste
tidsobjektetda du mottok et nyttmusobjekt. - Og hvilket var det siste
mus-elementetda du mottok et nytttids-element.
Dette vil gjøre det mulig for deg å:
- ikke sende en
mouse itemnedstrøms når musen ikke beveger seg på skjermen. - ikke sende et
mouse itemnedstrøms mens det ikke er utgitt et nytttime itemfra eachSecond$-strømmen.
Dette kan gjøres ved å bruke globale variabler. Men det er ikke måten RxJS gjør ting på. Jeg kjenner ikke til en måte å lagre det siste sendte elementet og bruke det i neste steg. Reduser-operatøren kan holde tilstanden: fra ett element sendt - til et annet, men hvordan kan vi bruke den egenskapen for å oppnå denne oppførselen? Disse strømmer må betraktes som uendelige. Hmm... det bør være en enklere måte å kombinere disse to strømmer på. Kanskje er det for tidlig... Jeg føler at hjernen min ikke vil tenke i strømmer :)
Så de 2 spørsmålene ble klargjort:
- hvilke er noen måter å begrense en mousemove-strøm på i Angular 2?
- kan jeg bruke en annen strøm for å kontrollere når jeg slipper mousemove-elementene? Hvis ja, kan denne "Kontrollstrømmen" være hvilken som helst strøm, eller er det begrensninger?
Tusen takk:)
Svar #1
Du er så nær! Ironisk nok er din magiske operatør er sample.
Den gamle varianten av sample (fra RxJS4) var overbelastet og kunne ta et tall som sitt argument. I RxJS5 (den som leveres med Angular2) har den blitt delt slik at det faktisk finnes to operatører sample og sampleTime. Den sistnevnte er den som tar et tidsargument og tar den siste hendelsen i et gitt tidsvindu når den sender ut.
const mouseMoveEachSecond$ = mouseMove$.sampleTime(1000);
Den første tar en Observable som sitt eneste argument og sender ut det siste elementet som mottas hver gang kontroll-Observableen sender ut.
dvs.
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));
Svar #2
hva med å importere throttleTime:
import { throttleTime } from 'rxjs/operators';
og bruk det deretter slik:
mousemouve$.pipe(
throttleTime(5000)
)
