Jeda rxjs interval

Nov 04 2020

Saya memiliki stopwatch sederhana, dengan menggunakan rxjs

Masalahnya adalah: tidak bisa mendapatkan cara menjeda aliran interval saya, dan kemudian melanjutkannya stackbiz

Jawaban

1 MrkSef Nov 04 2020 at 16:02

Saya telah melihat pertanyaan stopwatch cukup sering muncul sehingga saya pikir akan menarik untuk membuat observasi stopWatch kustom. The RxJS cara akan melaksanakan ini dengan beralih ke dalam dan keluar dari timer / interval.

Cara lain yang menarik untuk mengimplementasikannya adalah dengan menggunakan setTimeout. setTimeout seharusnya membutuhkan lebih sedikit memori karena kami tidak bersandar pada peralatan yang dapat diamati untuk mencapai tujuan pengaturan waktu kami

Bagaimana cara kerjanya? Dapat diamati khusus kami membuat aliran yang mengeluarkan angka di stopwatch dan dikendalikan oleh aliran terpisah (Di sini disebut control$). Jadi, saat control$memancarkan "MULAI", stopWatch akan dimulai, saat "STOP" berbunyi, stopwatch akan berhenti, dan saat "RESET", stopwatch akan menyetel penghitung kembali ke nol. Saat control$kesalahan atau selesai, stopwatch salah atau selesai.

Diimplementasikan dengan switchMap dan Timer

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

Diimplementasikan dengan setTimeout

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

StopWatch sedang Digunakan

Berikut adalah contoh penggunaan observable ini. Saya mengelola aliran kontrol melalui subjek, tetapi dapat dengan mudah digabungkan / memetakan peristiwa DOM atau semacamnya.

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

StopWatch in Use # 2

Ini mengontrol stopwatch dengan setTimeoutalih - alih 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);
1 JanRecker Nov 04 2020 at 12:36

Lihatlah solusi saya di stackblitz ini

Komponen harus berlangganan ke StopWatch-Service. Saya tidak suka gagasan memberi layanan nilai dan kemudian layanan MENGUBAH nilainya secara implisit. Untuk itu saya bekerja dengan cara eksplisit untuk mendapatkan stopWatch yang diperbarui (sebagai observasi).

Saya bekerja dengan "timer" bukan "interval", karena "interval" akan mengeluarkan nilai pertama (a 0) setelah satu detik, oleh karena itu stopWath saya akan mengalami penundaan,

Ada sedikit trik. Ada variabel pribadi "timer $", BehaviorSubject. Dan segera setelah penghitung dimulai, saya memulai pengatur waktu, dan berlangganan. Dalam langganan itu setiap pengatur waktu, akan mengeluarkan nilai baru untuk BehaviorSubject.

Sekarang saya juga menyimpan langganan.
Jika saya ingin menghentikan semuanya, saya hanya berhenti berlangganan dari "timer". Akibatnya jam berhenti. Tetapi karena ini semacam dipisahkan dari behaviourSubject timer$, seseorang masih akan menyimpan nilai terakhir.

Atau dengan kata lain:
The BehaviorSubject hidup selamanya, konsumen tidak pernah berhenti berlangganan (hanya jika dia melakukannya sendiri). Dan saya semacam "melampirkan" dan "melepaskan" fungsi pengatur waktu ke sana, kapan pun penghitungan harus dimulai atau dihentikan.

Ngomong-ngomong, merupakan kebiasaan yang baik untuk selalu memastikan bahwa komponen Anda akan berhenti berlangganan dari semua observasi yang berjalan, saat komponen dimusnahkan. Jika itu tidak dilakukan, maka langganan yang masih aktif dapat mengakibatkan kinerja atau bahkan masalah yang lebih buruk dalam aplikasi.

Saya harap ini sedikit membantu

Salam hangat