Subjek vs BehaviorSubject vs ReplaySubject di Angular


124

Saya telah mencari untuk memahami 3 itu:

Subjek , subjek Perilaku , dan subjek Putar Ulang . Saya ingin menggunakannya dan mengetahui kapan dan mengapa, apa keuntungan menggunakan mereka dan meskipun saya telah membaca dokumentasi, menonton tutorial dan mencari di Google, saya gagal untuk memahami hal ini.

Jadi apa tujuan mereka? Kasus dunia nyata akan sangat dihargai karena bahkan tidak perlu kode.

Saya lebih suka penjelasan yang bersih bukan hanya "a + b => c Anda berlangganan ...."

Terima kasih


1
Sudah ada pertanyaan dengan subjek perilaku dengan observasi; stackoverflow.com/questions/39494058/… dan dokumentasi tentang subjek replay jelas di github.com/Reactive-Extensions/RxJS/blob/master/doc/api/…
eko

Ada pemaparan yang relatif menyeluruh tentang mata pelajaran dalam Rxj dalam jawaban ini , yang melengkapi jawaban dari peeksilet dengan baik. Ini termasuk juga detail penting tentang perilaku setelah penghentian, jadi ada baiknya untuk melihat-lihat.
pengguna3743222

Jawaban:


278

Itu benar-benar bermuara pada perilaku dan semantik. Dengan

  • Subject- pelanggan hanya akan mendapatkan nilai yang diterbitkan yang dipancarkan setelah berlangganan. Tanyakan pada diri Anda, apakah itu yang Anda inginkan? Apakah pelanggan perlu mengetahui sesuatu tentang nilai sebelumnya? Jika tidak, maka Anda dapat menggunakan ini, jika tidak pilih salah satu dari yang lain. Misalnya, dengan komunikasi komponen-ke-komponen. Katakanlah Anda memiliki komponen yang menerbitkan acara untuk komponen lain dengan satu klik tombol. Anda dapat menggunakan layanan dengan subjek untuk berkomunikasi.

  • BehaviorSubject- nilai terakhir di-cache. Pelanggan akan mendapatkan nilai terbaru setelah berlangganan awal. Semantik untuk mata pelajaran ini adalah untuk merepresentasikan nilai yang berubah dari waktu ke waktu. Misalnya pengguna yang masuk. Pengguna awal mungkin pengguna anonim. Tapi begitu pengguna masuk, nilai baru adalah status pengguna yang diautentikasi.

    Ini BehaviorSubjectdiinisialisasi dengan nilai awal. Ini terkadang penting untuk preferensi pengkodean. Katakanlah misalnya Anda menginisialisasi dengan null. Kemudian dalam langganan Anda, Anda perlu melakukan pemeriksaan null. Mungkin oke, atau mungkin mengganggu.

  • ReplaySubject- dapat menyimpan hingga sejumlah emisi tertentu. Setiap pelanggan akan mendapatkan semua nilai cache setelah berlangganan. Kapan Anda membutuhkan perilaku ini? Sejujurnya, saya tidak membutuhkan perilaku seperti itu, kecuali untuk kasus berikut:

    Jika Anda menginisialisasi a ReplaySubjectdengan ukuran buffer sebesar 1, maka sebenarnya berperilaku seperti a BehaviorSubject. Nilai terakhir selalu disimpan dalam cache, sehingga berfungsi seperti nilai yang berubah seiring waktu. Dengan ini, tidak perlu ada nullpemeriksaan seperti dalam kasus yang BehaviorSubjectdiinisialisasi dengan a null. Dalam hal ini, tidak ada nilai yang dikirimkan ke pelanggan sampai penerbitan pertama.

Jadi itu benar-benar tergantung pada perilaku yang Anda harapkan (seperti yang akan digunakan). Sebagian besar waktu Anda mungkin ingin menggunakan a BehaviorSubjectkarena apa yang sebenarnya ingin Anda wakili adalah semantik "nilai dari waktu ke waktu". Tapi saya pribadi tidak melihat ada yang salah dengan substitusi yang ReplaySubjectdiinisialisasi dengan 1.

Apa yang ingin Anda hindari adalah menggunakan vanilla Subjectketika yang sebenarnya Anda butuhkan adalah perilaku cache. Ambil contoh Anda menulis penjaga rute atau tekad. Anda mengambil beberapa data di penjaga itu dan mengaturnya dalam sebuah layanan Subject. Kemudian di komponen yang dirutekan Anda berlangganan subjek layanan untuk mencoba mendapatkan nilai yang dipancarkan di penjaga. OOP. Dimana nilainya? Itu sudah dipancarkan, DUH. Gunakan subjek "caching"!

Lihat juga:


1
Ini singkat dan mudah untuk memahami perbedaannya. Ketika nilai berubah dalam layanan dan komponen juga berubah yang nilainya ditampilkan, maka BehaviourSubjects atau Replay Subject adalah solusinya.
Saiyaff Farouk

1
Terima kasih! ReplaySubjectdengan ukuran buffer 1 adalah apa yang saya butuhkan. Saya memiliki penjaga rute yang membutuhkan nilai, tetapi harus menunggu emisi pertama. Jadi a BehaviorSubjecttidak memotongnya, karena saya tidak menginginkan nilai awal ( nulljuga tidak akan berfungsi karena saya menggunakannya untuk menandakan keadaan)
menehune23

1
@ menehune23 Saya juga membutuhkan ReplaySubject untuk resolvekelas penjaga sudut . Layanan data saya bisa saja asinkron, atau sinkron (jika data sudah diambil). Jika sinkron, Subject.next () telah diaktifkan sebelum resolvefungsinya dikembalikan dan disubscribe oleh Angular secara internal. BehaviourSubject mungkin akan bekerja, tetapi saya harus memanggil secara eksplisit complete()dan juga menambahkan nullpemeriksaan untuk nilai awal. Apa yang berhasil adalah baru ReplaySubject<DataType>(1) danresolveSubject.asObservable().take(1).map(....)
Drenai

1
Saya menggunakan ReplaySubject dengan ukuran buffer 1 tetapi untuk beberapa alasan ketika saya mendapatkan Observable dengan .asObservable()Observable mengirim nilai nullke pelanggan sebelum saya memanggil next()ReplaySubject saya. Saya pikir itu tidak seharusnya memiliki nilai awal tidak seperti BehaviorSubject?
Kyle V.

2
Saya rasa contoh yang cukup mudah yang dapat Anda sebutkan untuk subjek ulangan adalah untuk skenario "ruang obrolan" atau lobi permainan di mana Anda ingin para penggabung baru melihat 10 pesan terakhir.
Yakobus

16

Ringkasan praktis dari berbagai jenis yang dapat diamati, penamaan non intuitif saya tahu lol .

  • Subject - Pelanggan hanya akan mendapatkan nilai yang dipublikasikan setelahnya-setelah langganan dibuat.
  • BehaviorSubject - Pelanggan baru mendapatkan nilai publikasi terakhir ATAU nilai awal segera setelah berlangganan.
  • ReplaySubject - Pelanggan baru mendapatkan semua nilai yang dipublikasikan sebelumnya segera setelah berlangganan

1-n nilai yang dipublikasikan? Jadi jika ada 2 nilai yang dipublikasikan, sebuah ReplaySubject akan menghasilkan -1 nilai yang dipublikasikan ???
Jason Cheng

@JasonCheng tidak, itu mengambil semua nilai yang diterbitkan sebelumnya setelah berlangganan, perbarui jawaban :)
Ricky Boyce

11
  1. Subjek : Saat berlangganan, selalu mendapatkan data yang didorong setelah berlangganan, yaitu nilai yang didorong sebelumnya tidak diterima .
const mySubject = new Rx.Subject();

mySubject.next(1);

const subscription1 = mySubject.subscribe(x => {
  console.log('From subscription 1:', x);
});

mySubject.next(2);

const subscription2 = mySubject.subscribe(x => {
  console.log('From subscription 2:', x);
});

mySubject.next(3);

subscription1.unsubscribe();

mySubject.next(4);

Dengan contoh ini, inilah hasil yang akan dicetak di konsol:

From subscription 1: 2
From subscription 1: 3
From subscription 2: 3
From subscription 2: 4

Perhatikan bagaimana langganan yang datang terlambat kehilangan beberapa data yang didorong ke subjek.

  1. Putar ulang subjek : dapat membantu dengan menjaga buffer dari nilai sebelumnya yang akan dipancarkan ke langganan baru.

Berikut adalah contoh penggunaan untuk memutar ulang subjek di mana a buffer of 2 previous valuesdisimpan dan dipancarkan pada langganan baru:

const mySubject = new Rx.ReplaySubject(2);

mySubject.next(1);
mySubject.next(2);
mySubject.next(3);
mySubject.next(4);

mySubject.subscribe(x => {
  console.log('From 1st sub:', x);
});

mySubject.next(5);

mySubject.subscribe(x => {
  console.log('From 2nd sub:', x);
});

Inilah yang memberi kami di konsol:

From 1st sub: 3
From 1st sub: 4
From 1st sub: 5
From 2nd sub: 4
From 2nd sub: 5
  1. Subjek perilaku : mirip dengan subjek ulangan, tetapi hanya akan memancarkan kembali nilai yang terakhir dikeluarkan, atau nilai default jika tidak ada nilai yang telah dikeluarkan sebelumnya:
const mySubject = new Rx.BehaviorSubject('Hey now!');

mySubject.subscribe(x => {
  console.log('From 1st sub:', x);
});

mySubject.next(5);

mySubject.subscribe(x => {
  console.log('From 2nd sub:', x);
});

Dan hasilnya:

From 1st sub: Hey now!
From 1st sub: 5
From 2nd sub: 5

Referensi: https://alligator.io/rxjs/subjects/


4

Dari: Randall Koutnik buku “Bangun Situs Web Reaktif dengan RxJS.” :

Sebuah Subyek adalah obyek yang turbocharged diamati. Pada intinya, Subjek bertindak seperti pengamatan biasa, tetapi setiap langganan terhubung ke sumber yang sama. Subjek juga adalah pengamat dan memiliki metode berikutnya, error, dan done untuk mengirim data ke semua pelanggan sekaligus. Karena subjek adalah pengamat, mereka dapat diteruskan langsung ke panggilan berlangganan, dan semua peristiwa dari pengamatan asli akan dikirim melalui subjek ke pelanggannya.

Kita dapat menggunakan ReplaySubject untuk melacak sejarah. Sebuah ReplaySubject merekam n peristiwa terakhir dan mengirimkannya kembali ke setiap pelanggan baru. Misalnya di aplikasi chat. Kita dapat menggunakannya untuk melacak catatan riwayat obrolan sebelumnya.

Sebuah BehaviorSubject adalah versi sederhana dari ReplaySubject . The ReplaySubject disimpan jumlah sewenang-wenang peristiwa, BehaviorSubject hanya mencatat nilai dari acara terbaru. Setiap kali BehaviorSubject merekam langganan baru, ia memancarkan nilai terbaru ke pelanggan serta nilai baru yang diteruskan. BehaviorSubject berguna saat menangani satu unit negara, seperti opsi konfigurasi.


1

Jawaban yang paling banyak mendapat suara positif jelas salah dengan menyatakan bahwa:

"Jika Anda menginisialisasi a ReplaySubjectdengan ukuran buffer 1, maka sebenarnya berperilaku seperti BehaviorSubject"


Ini tidak sepenuhnya benar; periksa posting blog yang bagus ini tentang perbedaan antara keduanya. Misalnya jika Anda berlangganan ke selesai BehaviorSubject, Anda tidak akan menerima nilai terakhir tetapi untuk ReplaySubject(1)Anda akan menerima nilai terakhir.

Inilah perbedaan penting yang tidak boleh diabaikan:

const behavior = new BehaviorSubject(null);
const replay = new ReplaySubject(1);

behavior.skip(1).subscribe(v => console.log('BehaviorSubject:', v));
replay.subscribe(v => console.log('ReplaySubject:', v));

behavior.next(1);
behavior.next(2);
behavior.complete();
behavior.subscribe(v => console.log('Late B subscriber:', v));

replay.next(1);
replay.next(2);
replay.complete();
replay.subscribe(v => console.log('Late R subscriber:', v));

Lihat contoh kode ini di sini yang berasal dari entri blog hebat lainnya tentang topik tersebut.


0
     // ***********Subject  concept ***********
    let subject = new Subject<string>();


    subject.next("Eureka");
    subject.subscribe((data) => {
      console.log("Subscriber 1 got data >>>>> "+ data);
    });
    subject.subscribe((data) => {
      console.log("Subscriber 2 got data >>>>> "+ data);
    });

       // ********behaviour subject*********
    // Behavior subjects need a first value
let subject1 = new BehaviorSubject<string>("First value");


subject1.asObservable().subscribe((data) => {
  console.log("First subscriber got data behaviour subject>>>>> "+ data);
});
subject1.next("Second value")
  • Subjek - Pelanggan hanya akan mendapatkan nilai yang dipublikasikan di atasnya-setelah langganan dibuat.
  • BehaviorSubject - Pelanggan baru mendapatkan nilai terakhir yang dipublikasikan ATAU nilai awal segera setelah berlangganan.
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.