Mengapa setTimeout () membuat aplikasi saya lamban, tetapi timer Rxjs (). Berlangganan (...) tidak?

9

Saya memiliki komponen, yang "malas memuat" beberapa komentar, pada interval 100ms.

Ketika saya menggunakan setTimeout, itu sangat lamban.

komponen

<div *ngFor="let post of posts">
   <app-post [post]="post" ></app-post>
</div>

Ini membuat Aplikasi saya lamban (rata-rata 14, waktu siaga 51100 ms):

while(this.postService.hasPosts()){
  setTimeout(()=> {
   this.posts.push(this.postService.next(10));
  },100);
}

Ini membuat Aplikasi saya lancar (rata-rata 35, waktu siaga 40800 ms)

while(this.postService.hasPosts()){
  timer(100).subscribe(()=> {
    this.posts.push(this.postService.next(10));
  });
}

Apakah ada penjelasan, mengapa timer rxjs, bekerja jauh lebih baik?

Saya melakukan analisis runtime dengan firefox. Pada contoh pertama, frame rate turun menjadi 14 fps. Dalam contoh lain, 35 fps.

Bahkan waktu idle 20% lebih rendah.

Metode ini bahkan lebih mulus (rata-rata 45, waktu siaga 13500 ms):

interval(100).pipe(takeWhile(this.postService.hasPosts()).subscribe(()=> {
    this.posts.push(this.postService.next(10));
  });
}
Masalah Luxus
sumber

Jawaban:

2

Solusi terakhir Anda adalah satu-satunya yang benar.

Dua solusi lainnya seharusnya tidak bekerja seperti yang Anda harapkan. Sebenarnya, ini akan menghasilkan loop tak terbatas.

Ini karena cara kerja eventloop JavaScript . Gambar berikut menunjukkan model runtime JavaScript (Gambar diambil dari sini ):

masukkan deskripsi gambar di sini

Bagian yang relevan bagi kami adalah stackdan queue. JavaScript runtime memproses pesan di Internet queue. Setiap pesan dikaitkan dengan fungsi yang dipanggil saat pesan diproses.

Untuk stack, setiap panggilan fungsi membuat bingkai di stack yang berisi argumen fungsi dan variabel lokal. Jika suatu fungsi memanggil fungsi lain, bingkai baru didorong di atas tumpukan. Ketika suatu fungsi mengembalikan bingkai atas muncul dari tumpukan.

Sekarang jika stack kosong, JavaScript runtime akan memproses pesan berikutnya pada queue(yang tertua).

Jika Anda menggunakan setTimeout(() => doSomething(),100), doSomething()fungsi akan ditambahkan ke antrian setelah 100 milidetik. Ini adalah alasan mengapa 100 milidetik bukan waktu yang terjamin tetapi waktu yang minimal. Karena itu Anda doSomething methodhanya dipanggil, jika tumpukannya kosong dan tidak ada yang lain dalam antrian.

Tetapi karena Anda mengulangi dalam loop sementara dan kondisi Anda tergantung pada kode di dalam Anda setTimeout, Anda telah membuat loop tak terbatas karena tumpukan tidak akan kosong dan karena itu this.posts.push(this.postService.next(10));kode Anda tidak akan pernah dipanggil.

Untuk implementasi RxJS, hal yang sama berlaku. Mereka menggunakan penjadwal untuk menangani waktu. Ada implementasi internal scheduler yang berbeda di RxJS, tetapi seperti yang dapat kita lihat dalam implementasi untuk intervaldan timer, jika kita tidak menentukan scheduler, defaultnya adalah asyncScheduler. Jadwal asyncScheduler bekerja dengan setIntervalyang berfungsi seperti setTimeoutdisebutkan di atas, dan mendorong pesan lain di antrian.

Saya mencoba dua solusi Anda dengan loop sementara dan yang pertama benar-benar membeku browser saya sedangkan yang kedua adalah super laggy tetapi bisa mengeluarkan sesuatu ke konsol di dalam loop sementara. Saya sebenarnya tidak tahu mengapa yang kedua sedikit lebih banyak performan, tetapi keduanya bukan yang sebenarnya Anda inginkan. Anda telah menemukan solusi yang bagus dan saya harap jawaban ini dapat membantu Anda memahami mengapa solusi pertama berkinerja buruk.

Max K
sumber