Rxjs aralığını duraklat
Rxjs kullanarak basit bir kronometrem var
Sorun şu: aralığımın bir akışını nasıl duraklatacağımı ve sonra buna devam edemiyorum stackbiz
Yanıtlar
Kronometre sorularının yeterince sık sorulduğunu gördüm ve gözlemlenebilir özel bir stopWatch oluşturmanın ilginç olacağını düşündüm. RxJS yolu, bunu zamanlayıcılara / aralıklara girip çıkarak uygulamak olacaktır.
Bunu gerçekleştirmenin bir başka ilginç yolu da setTimeout kullanmaktır. setTimeout, zamanlama hedeflerimizi gerçekleştirmek için gözlemlenebilir aygıta dayanmadığımız için aslında biraz daha az bellek gerektirmelidir.
Bu nasıl işleyecek? Özel gözlemlenebilir cihazımız, sayıyı kronometreye veren ve ayrı bir akış tarafından kontrol edilen bir akış oluşturur (Burada denir control$). Yani control$"START" mesajı verdiğinde, stopWatch başlar, "STOP" mesajı verdiğinde, kronometre durur ve "RESET" mesajı verdiğinde kronometre sayacı sıfıra geri getirir. Ne zaman control$hata veya tamamlamalar, kronometre hata veya tamamlamalar.
SwitchMap ve Timer ile uygulandı
function createStopwatch(control$: Observable<string>, interval = 1000): Observable<number>{
return defer(() => {
let toggle: boolean = false;
let count: number = 0;
const endTicker$ = new Subject(); const ticker = () => { return timer(0, interval).pipe( takeUntil(endTicker$),
map(x => count++)
)
}
return control$.pipe( tap({ next: _ => {/*Do nothing*/}, complete: () => { endTicker$.next();
endTicker$.complete(); }, error: err => { endTicker$.next();
endTicker$.complete();
}
}),
filter(control =>
control === "START" ||
control === "STOP" ||
control === "RESET"
),
switchMap(control => {
if(control === "START" && !toggle){
toggle = true;
return ticker();
}else if(control === "STOP" && toggle){
toggle = false;
return EMPTY;
}else if(control === "RESET"){
count = 0;
if(toggle){
return ticker();
}
}
return EMPTY;
})
);
});
}
SetTimeout ile uygulandı
function createStopwatch(control: Observable<string>, interval = 1000): Observable<number> {
return new Observable(observer => {
let count: number = 0;
let tickerId: number = null;
const clearTicker = () => {
if(tickerId != null){
clearTimeout(tickerId);
tickerId = null;
}
}
const setTicker = () => {
const recursiveTicker = () => {
tickerId = setTimeout(() => {
observer.next(count++);
recursiveTicker();
}, interval);
}
clearTicker();
observer.next(count++);
recursiveTicker();
}
control.subscribe({
next: input => {
if(input === "START" && tickerId == null){
setTicker();
}else if(input === "STOP"){
clearTicker();
}else if(input === "RESET"){
count = 0;
if(tickerId != null){
setTicker();
}
}
},
complete: () => {
clearTicker();
observer.complete();
},
error: err => {
clearTicker();
observer.error(err);
}
});
return {unsubscribe: () => clearTicker()};
});
}
Kullanımda StopWatch
İşte bu gözlemlenebilir kullanımın bir örneği. Kontrol akışını bir konu aracılığıyla yönetiyorum, ancak DOM olayları veya bir şekilde kolayca birleştirilebilir / eşleştirilebilir.
const control$ = new Subject<string>();
createStopwatch(control$, 250).subscribe(console.log); // We send a new action to our control stream every 1 second const actions = ["START", "STOP", "START", "RESET", "START"] zip(from(actions), interval(1000)).pipe( map((x,y) => x), finalize(() => { // After 5 seconds, unsubscribe via the control // If our control finishes in any way ( // completes, errors, or is unsubscribed), our // sopwatch reacts by doing the same. control$.complete();
})
).subscribe(x => control$.next(x));
Kullanımda StopWatch # 2
Bu, kronometreyi setTimeoutyerine ile kontrol eder interval.
const control$ = new Subject<string>();
createStopwatch(control$, 250).subscribe(console.log); // We send a new action to our control stream every 1 second const actions = ["START", "STOP", "START", "RESET", "START"] actions.forEach((val, index) => { setTimeout(() => { control$.next(val);
},
index * 1000);
})
// Unsubscribe via the control
setTimeout(() => {
control$.complete();
}, actions.length * 1000);
Bu stackblitz'deki çözümüme bir göz atın
Bileşen, StopWatch-Hizmetine abone olmalıdır. Bir hizmete değer verme fikrinden hoşlanmıyorum ve ardından hizmet değeri örtük olarak DEĞİŞTİRİYOR. Bu nedenle, güncellenmiş stopWatch'ı (gözlemlenebilir olarak) almak için açık bir yolla çalışıyorum.
"İnterval" yerine "timer" ile çalışıyorum, çünkü "interval" bir saniyeden sonra ilk değeri (a 0) yayacaktı, bu nedenle stopWath'imde bir gecikme olacaktı.
Küçük bir numara var. Bir BehaviorSubject olan "timer $" özel değişkeni vardır. Ve sayaç başlar başlamaz, bir zamanlayıcı başlatıyorum ve ona abone oluyorum. Bu abonelikte, zamanlayıcının her yayını, BehaviorSubject için yeni bir değer yayınlayacaktır.
Şimdi aboneliği de saklıyorum.
Her şeyi durdurmak istersem, sadece "zamanlayıcı" üyeliğinden çıkırım. Sonuç olarak saat durur. Ancak davranıştan bir tür ayrıştırılmış olduğundan timer$, son değeri yine de saklamış olacaktır.
Veya farklı bir şekilde söylemek gerekirse:
BehaviorSubject sonsuza kadar yaşar, tüketici asla aboneliğinden çıkmaz (sadece kendisi yaparsa). Ve sayımın başlaması veya durması gerektiğinde zamanlayıcı işlevini ona "ekliyorum" ve "bağlantısını kaldırıyorum".
Bu arada, bileşen yok edildiğinde bileşeninizin çalışan tüm gözlemlenebilir öğelerden çıkacağından emin olmak iyi bir alışkanlıktır. Bu yapılmazsa, hala aktif olan abonelikler bir uygulamada performansa veya daha da kötü sorunlara neden olabilir.
umarım biraz yardımcı olur
sevgilerimle