Saya memiliki layanan Angular 2:
import {Storage} from './storage';
import {Injectable} from 'angular2/core';
import {Subject} from 'rxjs/Subject';
@Injectable()
export class SessionStorage extends Storage {
private _isLoggedInSource = new Subject<boolean>();
isLoggedIn = this._isLoggedInSource.asObservable();
constructor() {
super('session');
}
setIsLoggedIn(value: boolean) {
this.setItem('_isLoggedIn', value, () => {
this._isLoggedInSource.next(value);
});
}
}
Semuanya bekerja dengan baik. Tapi saya punya komponen lain yang tidak perlu berlangganan, hanya perlu mendapatkan nilai isLoggedIn saat ini pada titik waktu tertentu. Bagaimana saya bisa melakukan ini?
javascript
angular
rxjs
Baconbeastnz
sumber
sumber
getValue()
adalah bendera merah BESAR Anda melakukan sesuatu yang salah. Itu ada di sana sebagai pintu keluar. Secara umum semua yang Anda lakukan dengan RxJS harus bersifat deklaratif.getValue()
sangat penting. Jika Anda menggunakangetValue()
, ada kemungkinan 99,9% Anda melakukan sesuatu yang salah atau aneh.BehaviorSubject<boolean>(false)
dan suka mengaktifkannya?foo$
adalahBehaviorSubject
(yaitu didefinisikan sebagaiObservable
dan mungkin panas atau dingin dari sumber yang ditangguhkan). Namun karena Anda kemudian pergi ke penggunaan.next
pada$foo
dirinya sendiri itu berarti pelaksanaan Anda bergantung pada hal itu menjadi suatuBehaviorSubject
sehingga tidak ada pembenaran untuk tidak hanya menggunakan.value
untuk mendapatkan nilai saat ini di tempat pertama.Satu-satunya cara Anda harus mendapatkan nilai "keluar dari" Subjek yang Dapat Diamati / adalah dengan berlangganan!
Jika Anda menggunakan
getValue()
Anda melakukan sesuatu yang penting dalam paradigma deklaratif. Itu ada di sana sebagai pintu keluar darurat, tetapi 99,9% dari waktu Anda TIDAK boleh menggunakangetValue()
. Ada beberapa hal menarik yanggetValue()
akan dilakukan: Ini akan melempar kesalahan jika subjek telah berhenti berlangganan, itu akan mencegah Anda dari mendapatkan nilai jika subjek mati karena itu salah, dll. Tapi, sekali lagi, itu ada sebagai pelarian menetas untuk keadaan langka.Ada beberapa cara untuk mendapatkan nilai terbaru dari Subjek atau Dapat Diamati dengan cara "Rx-y":
BehaviorSubject
: Tapi sebenarnya berlangganan itu . Ketika Anda pertama kali berlanggananBehaviorSubject
akan secara sinkron mengirim nilai sebelumnya diterima atau diinisialisasi dengan.ReplaySubject(N)
: Ini akan men-cacheN
nilai dan memutar ulang ke pelanggan baru.A.withLatestFrom(B)
: Gunakan operator ini untuk mendapatkan nilai terbaru dari yang dapat diamatiB
saatA
dipancarkan. Akan memberi Anda kedua nilai dalam array[a, b]
.A.combineLatest(B)
: Gunakan operator ini untuk mendapatkan nilai terbaru dariA
danB
setiap kali salah satuA
atauB
memancarkan. Akan memberi Anda kedua nilai dalam array.shareReplay()
: Membuat multicast yang Dapat Diobservasi melalui aReplaySubject
, tetapi memungkinkan Anda untuk mencoba lagi kesalahan yang dapat diamati. (Pada dasarnya itu memberi Anda perilaku caching janji-y).publishReplay()
,publishBehavior(initialValue)
,multicast(subject: BehaviorSubject | ReplaySubject)
, Dll: operator lain bahwa leverageBehaviorSubject
danReplaySubject
. Rasa berbeda dari hal yang sama, mereka pada dasarnya multicast sumber yang dapat diamati dengan menyalurkan semua pemberitahuan melalui subjek. Anda perlu meneleponconnect()
untuk berlangganan ke sumber dengan subjek.sumber
click$.mergeMap(() => behaviorSubject.take(1))
untuk menyelesaikan masalah Anda juga.AuthenticationService
yang menggunakanBehaviourSubject
untuk menyimpan status login saat ini (boolean
true
ataufalse
). Ini memperlihatkan sebuahisLoggedIn$
diamati untuk pelanggan yang ingin tahu kapan negara berubah. Itu juga memperlihatkanget isLoggedIn()
properti, yang mengembalikan keadaan login saat ini dengan memanggilgetValue()
yang mendasarinyaBehaviourSubject
- ini digunakan oleh penjaga otentikasi saya untuk memeriksa keadaan saat ini. Sepertinya ini masuk akalgetValue()
bagiku ...?Saya memiliki situasi yang sama di mana pelanggan yang terlambat berlangganan ke Subjek setelah nilainya tiba.
Saya menemukan ReplaySubject yang mirip dengan BehaviorSubject berfungsi seperti pesona dalam kasus ini. Dan di sini ada tautan ke penjelasan yang lebih baik: http://reactivex.io/rxjs/manual/overview.html#replaysubject
sumber
next()
fungsinya belum dipanggil, sedangkan BehaviourSubject tidak. Emit langsung sangat berguna untuk menerapkan nilai default ke tampilan, ketika BehaviourSubject digunakan sebagai sumber data yang dapat diamati dalam layanan misalnyaAnda dapat memeriksa artikel lengkap tentang cara mengimplementasikannya dari sini. https://www.imkrish.com/how-to-get-current-value-of-observable-in-a-clean-way/
sumber
Saya mengalami masalah yang sama dalam komponen anak di mana awalnya harus memiliki nilai saat ini dari Subjek, kemudian berlangganan Subjek untuk mendengarkan perubahan. Saya hanya mempertahankan nilai saat ini di Layanan sehingga tersedia untuk komponen untuk diakses, misalnya:
Komponen yang membutuhkan nilai saat ini dapat mengaksesnya dari layanan, yaitu:
Tidak yakin apakah ini praktik yang benar :)
sumber
async
pipa.Sebuah serupa mencari jawaban downvoted. Tapi saya pikir saya bisa membenarkan apa yang saya sarankan di sini untuk kasus-kasus terbatas.
Meskipun benar bahwa yang diamati tidak memiliki nilai saat ini , sangat sering itu akan memiliki nilai yang segera tersedia . Misalnya dengan toko redux / fluks / akita Anda dapat meminta data dari toko pusat, berdasarkan sejumlah yang dapat diobservasi dan nilai itu umumnya akan segera tersedia.
Jika demikian, maka ketika Anda
subscribe
, nilainya akan segera kembali.Jadi misalkan Anda melakukan panggilan ke layanan, dan pada penyelesaian Anda ingin mendapatkan nilai terbaru dari sesuatu dari toko Anda, yang mungkin tidak akan memancarkan :
Anda mungkin mencoba melakukan ini (dan Anda harus sedapat mungkin menjaga barang-barang 'di dalam pipa'):
Masalah dengan ini adalah bahwa hal itu akan memblokir sampai yang diamati diamati nilai sekunder, yang berpotensi tidak pernah.
Saya menemukan diri saya baru-baru ini perlu mengevaluasi yang dapat diamati hanya jika nilai segera tersedia , dan yang lebih penting saya harus dapat mendeteksi jika tidak. Saya akhirnya melakukan ini:
Perhatikan bahwa untuk semua hal di atas saya menggunakan
subscribe
untuk mendapatkan nilai (seperti @Ben membahas). Tidak menggunakan.value
properti, bahkan jika saya punyaBehaviorSubject
.sumber
Meskipun mungkin terdengar berlebihan, ini hanyalah solusi "mungkin" untuk menjaga tipe yang dapat diamati dan mengurangi ...
Anda selalu dapat membuat pengambil ekstensi untuk mendapatkan nilai saat ini dari Observable.
Untuk melakukan ini, Anda perlu memperluas
Observable<T>
antarmuka dalamglobal.d.ts
file deklarasi pengetikan. Kemudian implementasikan pengambil ekstensi dalam sebuahobservable.extension.ts
file dan akhirnya sertakan juga pengetikan dan ekstensi file ke aplikasi Anda.Anda dapat merujuk pada Jawaban StackOverflow ini untuk mengetahui cara memasukkan ekstensi ke aplikasi Angular Anda.
sumber
Anda dapat menyimpan nilai yang dipancarkan terakhir secara terpisah dari Observable. Kemudian bacalah saat dibutuhkan.
sumber
Cara terbaik untuk melakukannya adalah menggunakan
Behaviur Subject
, berikut ini sebuah contoh:sumber
Langganan dapat dibuat dan setelah barang yang dipancarkan pertama dimusnahkan. Pipa adalah fungsi yang menggunakan Observable sebagai input dan mengembalikan Observable lain sebagai output, sementara tidak memodifikasi observable pertama. 8.1.1 sudut. Paket:
"rxjs": "6.5.3"
,"rxjs-observable": "0.0.7"
sumber