Rumah >hujung hadapan web >tutorial js >10 fungsi RXJS yang perlu diketahui dengan contoh
Artikel ini dikaji semula oleh Florian Rappl dan Moritz Kröger. Terima kasih kepada semua pengulas rakan sebaya di SitePoint untuk membuat kandungan SitePoint sempurna!
Sebagai minat dalam pengaturcaraan reaktif berfungsi (FRP) tumbuh, RXJS telah menjadi salah satu perpustakaan JavaScript yang paling popular dalam paradigma ini. Dalam artikel ini, kami akan meneroka sepuluh fungsi mesti tahu dalam RXJS.
Nota: Artikel ini mengandaikan bahawa anda sudah biasa dengan asas -asas RXJS, seperti yang diterangkan dalam artikel "Bermula dengan pengaturcaraan reaktif berfungsi dengan RXJS".mata utama
map()
, filter()
, dan reduce()
, operasi array cermin, tetapi digunakan untuk aliran nombor yang memancarkan nilai dari masa ke masa. take()
flatMap()
adalah penting untuk mengendalikan struktur data yang kompleks dan menguruskan pelbagai aliran secara berasingan, menjadikannya kritikal untuk tugas pengaturcaraan reaktif lanjutan. switch()
concat()
dan merge()
boleh digunakan untuk menggabungkan pelbagai aliran, masing -masing memainkan peranan yang berbeza dalam pengurusan aliran dan penyegerakan data. combineLatest()
Fungsi takeUntil()
Objek Stream -atau yang boleh dilihat dalam Jargon -sama -sama pendengar acara: Kedua -duanya menunggu sesuatu yang berlaku dan memberitahu anda apabila ia berlaku. Satu siri pemberitahuan asynchronous yang diperoleh dari pendengar onclick adalah contoh sempurna aliran data.
Dengan kata lain, objek yang dapat dilihat tidak lebih daripada array yang diisi dari masa ke masa.
Unsur -unsur array ini boleh datang dari hampir mana -mana sahaja: sistem fail, peristiwa DOM, panggilan API, dan juga data segerak yang ditukar seperti tatasusunan. Secara asasnya, pengaturcaraan reaktif tidak lebih daripada menggunakan objek yang dapat dilihat sebagai blok bangunan program.
Hubungan dengan Array
Sebaliknya, objek yang dapat dilihat ditakrifkan oleh masa. Paling banyak anda boleh tahu bahawa aliran telah diterima setakat ini [1, 2, 3]. Anda tidak dapat memastikan jika anda akan mendapat 4 -atau tidak -dan ia adalah sumber data, bukan program anda, yang menentukannya.
Hubungan antara aliran dan tatasusunan sangat mendalam bahawa kebanyakan sambungan reaktif berasal dari dunia pengaturcaraan berfungsi, di mana operasi senarai adalah teras.
Pertimbangkan aplikasi tugas biasa. Mari lihat persoalan bagaimana untuk memaparkan nama tugas yang belum selesai pengguna menggunakan RXJS:
<code class="language-javascript">const task_stream = // 创建所有数据库中任务的流 getTasks(). // 只获取此用户的任务 filter((task) => task.user_id == user_id). // 获取未完成的任务 filter((task) => !task.completed). // 只获取任务名称 map((task) => task.name) /* 任务如下所示: task = { user_id : number, completed : boolean, name : string } */</code>
Setakat ini, ini hanyalah lanjutan array, tetapi ia menunjukkan gaya fungsi pengaturcaraan reaktif.
Sifat deklaratif menjadi jelas dengan menambahkan fungsi yang lebih kompleks, "dunia nyata". Katakan kita mahu:
<code class="language-javascript">const task_stream = parameter_stream. debounce(1000). map((parameter) => { getTasks(). retry(3). filter((task) => task.user_id === user_id). filter((task) => task.completed === parameter). map((task) => task.name) }). flatMap(Rx.Observable.from). distinctUntilChanged(). update()</code>
Parameter_Stream memberitahu kami sama ada pengguna mahu menyelesaikan tugas atau belum selesai dan menyimpan pemilihan dalam parameter;
Debounce () Pastikan kami hanya memberi tumpuan kepada butang terakhir klik sesaat;sistem berskala;
pengendalian ralat mudah, langsung dan kuat.
penapis ()
ambil () / takeWhile ()
menerima panggilan balik sebagai parameter;
Jalankannya pada setiap elemen array yang anda panggil;Mengembalikan array baru di mana setiap elemen array asal digantikan oleh hasil yang dihasilkan oleh panggilan balik di atasnya.
<code class="language-javascript">const task_stream = // 创建所有数据库中任务的流 getTasks(). // 只获取此用户的任务 filter((task) => task.user_id == user_id). // 获取未完成的任务 filter((task) => !task.completed). // 只获取任务名称 map((task) => task.name) /* 任务如下所示: task = { user_id : number, completed : boolean, name : string } */</code>
di sini, kami menggunakan peta untuk menggantikan setiap objek pengguna dalam aliran masuk dengan setiap laman web pengguna.
rxjs juga membolehkan anda memanggil peta () sebagai pilih (). Kedua -dua nama merujuk kepada fungsi yang sama.
<code class="language-javascript">const task_stream = parameter_stream. debounce(1000). map((parameter) => { getTasks(). retry(3). filter((task) => task.user_id === user_id). filter((task) => task.completed === parameter). map((task) => task.name) }). flatMap(Rx.Observable.from). distinctUntilChanged(). update()</code>Ini hanya akan memilih pengguna yang laman webnya berakhir dengan "bersih" atau "org".
penapis () juga mempunyai alias di mana ().
3.
mengurangkan () sering merupakan operasi senarai asas yang paling membingungkan, kerana tidak seperti penapis () atau peta (), tingkah lakunya berbeza dengan penggunaan.
Biasanya, mengurangkan () mengambil koleksi nilai dan menukarkannya ke dalam satu titik data. Dalam contoh kami, kami akan menyediakannya dengan aliran nama laman web dan menggunakan mengurangkan () untuk menukar aliran itu menjadi objek yang mengira jumlah bilangan laman web yang kami dapati dan panjang namanya.
di sini, kami memudahkan aliran ke objek tunggal, yang menjejaki:
<code class="language-javascript">source. map((user) => user.website)</code>
berapa banyak laman web yang kita lihat;
ambil () dan takeWhile () melengkapkan fungsi asas aliran mudah.
kita boleh menggunakan imbasan () untuk memancarkan objek kami setiap kali kami menerima laman web, dan hanya mengambil () dua nilai pertama.
rxjs juga menyediakan TakeWhile (), yang membolehkan anda mendapatkan nilai sebelum ujian Boolean tertentu ditubuhkan. Kita boleh menggunakan TakeWhile () untuk menulis aliran di atas seperti ini:
<code class="language-javascript">source. map((user) => user.website). filter((website) => (website.endsWith('net') || website.endsWith('org')); })</code>Operasi aliran pesanan tinggi
Fungsi -fungsi ini hampir sama dengan operasi senarai biasa kecuali mereka bekerja pada objek yang dapat dilihat dan bukannya tatasusunan.
<code class="language-javascript">source. map((user) => user.website). filter((website) => (website.endsWith('net') || website.endsWith('org'))). reduce((data, website) => { return { count : data.count += 1, name_length : data.name_length += website.length } }, { count : 0, name_length : 0 })</code>
Sama seperti array boleh mengandungi data yang lebih kompleks daripada nilai mudah (seperti array atau objek), objek yang dapat dilihat juga boleh memancarkan data pesanan yang lebih tinggi, seperti janji atau objek lain yang dapat dilihat. Di sinilah alat yang lebih profesional dimainkan.
5.
... Malah, kita sudah menggunakannya!
Apabila kita menentukan aliran sumber, kita panggil daripromise () dan flatmap ():
daripromise;
rx.observable.from;<code class="language-javascript">source. map((user) => user.website). filter((website) => (website.endsWith('net') || website.endsWith('org'))). scan((data, website) => { return { count : data.count += 1, name_length : data.name_length += website.length } }, { count : 0, name_length : 0 }). take(2);</code>flatmap.
janji adalah bahawa ia hanya mewakili nilai masa depan. Ia tidak boleh mengembalikan pelbagai data tak segerak;
Ini bermakna apabila kita menggunakan rx.observable.frompromise () kita mendapat objek yang dapat dilihat yang memancarkan nilai tunggal -atau:
Apabila janji mengembalikan rentetan atau nombor, kita tidak perlu melakukan sesuatu yang istimewa. Walau bagaimanapun, apabila ia mengembalikan array (yang mana dalam kes kita), kita lebih suka membuat objek yang dapat dilihat yang memancarkan kandungan array dan bukannya array itu sendiri sebagai satu nilai.
Apabila menggunakan flatmap (), kita:
Ini merangkumi kod dalam pengantar pendek kami:
<code class="language-javascript">const task_stream = // 创建所有数据库中任务的流 getTasks(). // 只获取此用户的任务 filter((task) => task.user_id == user_id). // 获取未完成的任务 filter((task) => !task.completed). // 只获取任务名称 map((task) => task.name) /* 任务如下所示: task = { user_id : number, completed : boolean, name : string } */</code>
rxjs juga menyediakan alias untuk flatmap (): selectMany ().
<code class="language-javascript">const task_stream = parameter_stream. debounce(1000). map((parameter) => { getTasks(). retry(3). filter((task) => task.user_id === user_id). filter((task) => task.completed === parameter). map((task) => task.name) }). flatMap(Rx.Observable.from). distinctUntilChanged(). update()</code>
Menggabungkan pelbagai aliran
7.
Sambungan dan gabungan adalah dua cara yang paling biasa untuk menggabungkan sungai.gabungan mencipta aliran baru dari pelbagai aliran dengan memancarkan nilai mana -mana aliran aktif
Fikirkan tentang bercakap dengan dua orang pada masa yang sama di Facebook Messenger. Concat () adalah situasi di mana anda menerima mesej dari kedua -dua pihak tetapi melengkapkan perbualan dengan satu orang sebelum membalas kepada orang lain. Gabungan () adalah seperti membuat sembang kumpulan dan menerima dua aliran mesej pada masa yang sama.
Aliran
concat () akan mencetak semua nilai sumber1 dan hanya akan mula mencetak nilai Source2 selepas Source1 selesai.
<code class="language-javascript">source. map((user) => user.website)</code>menggabungkan () aliran akan mencetak nilai Source1 dan Source2 mengikut urutan yang diterima: ia tidak menunggu aliran pertama selesai sebelum memancarkan nilai aliran kedua.
8
Biasanya, kami ingin mendengar objek yang dapat dilihat yang memancarkan objek yang dapat dilihat, tetapi hanya memberi tumpuan kepada pelepasan terkini dari sumber.
Untuk tujuan ini, RXJS menyediakan suis.
Antara muka pengguna menyediakan beberapa kes penggunaan yang baik untuk suis (). Jika permohonan kami membuat permintaan setiap kali pengguna memilih apa yang mereka mahu cari, kami boleh mengandaikan bahawa mereka hanya mahu melihat hasil pemilihan terkini. Oleh itu, kami menggunakan Switch () untuk mendengar hanya untuk hasil pemilihan terkini.
Dengan cara ini, kita harus pastikan tidak membazirkan jalur lebar dan hanya pilih akses ke pelayan untuk kali terakhir pengguna membuat setiap saat. Fungsi yang kami gunakan untuk ini dipanggil debounce ()
Jika anda mahu pergi ke arah yang lain dan hanya ikuti pilihan pertama, anda boleh menggunakan Throttle (). Ia mempunyai API yang sama, tetapi berkelakuan sebaliknya.
Untuk demonstrasi, kami akan membuat menu drop-down yang lain dan membolehkan pengguna memilih ID item yang mereka mahu ambil.
Terdapat dua situasi. Apabila Pengguna:
Pemilihan akhir titik akhir pengguna;
Apabila mana -mana aliran memancarkan nilai, CombinElatest () mengambil nilai yang dipancarkan dan berpasangan dengan item terakhir yang dipancarkan oleh aliran lain dan mengeluarkan pasangan itu sebagai array.
<code class="language-javascript">const task_stream = // 创建所有数据库中任务的流 getTasks(). // 只获取此用户的任务 filter((task) => task.user_id == user_id). // 获取未完成的任务 filter((task) => !task.completed). // 只获取任务名称 map((task) => task.name) /* 任务如下所示: task = { user_id : number, completed : boolean, name : string } */</code>Ini lebih mudah untuk digambarkan dalam carta:
Gunakan zip untuk bertindak balas hanya kepada perubahan dalam dua aliran
<code class="language-javascript">const task_stream = parameter_stream. debounce(1000). map((parameter) => { getTasks(). retry(3). filter((task) => task.user_id === user_id). filter((task) => task.completed === parameter). map((task) => task.name) }). flatMap(Rx.Observable.from). distinctUntilChanged(). update()</code>jadi tunggu sehingga pengguna mengemas kini pemilihan bidang ID dan titik akhir, menggantikan CombinElatest () dengan zip ().
Tidak seperti CombinElatest (), zip () akan menunggu sehingga kedua -dua objek yang dapat dilihat memancarkan kandungan baru sebelum menghantar pelbagai nilai yang dikemas kini.
<code class="language-javascript">source. map((user) => user.website)</code>10
Akhirnya, TakeUntil () membolehkan kita mendengar aliran pertama sehingga aliran kedua mula memancarkan nilai.
Ringkasan
<code class="language-javascript">source. map((user) => user.website). filter((website) => (website.endsWith('net') || website.endsWith('org')); })</code>
Hanya menambah dimensi masa ke array membuka pintu kepada pemikiran baru mengenai program.
Mulakan dengan RXJS Lite, bersedia untuk merujuk kepada dokumentasi dan luangkan masa untuk melakukannya. Sebelum anda tahu, semuanya akan kelihatan seperti sungai ... kerana semuanya.
Soalan Lazim Mengenai Fungsi RXJS (FAQ)
Apakah perbezaan utama antara RXJS dan JavaScript tradisional?
Dalam RXJS, anda boleh membuat objek yang boleh dilihat menggunakan pembina baru () yang baru. Pembina ini mengambil fungsi sebagai hujah, yang dipanggil fungsi pelanggan, yang dilaksanakan apabila pada mulanya melanggan objek yang dapat dilihat. Berikut adalah contoh asas:
<code class="language-javascript">const task_stream = // 创建所有数据库中任务的流 getTasks(). // 只获取此用户的任务 filter((task) => task.user_id == user_id). // 获取未完成的任务 filter((task) => !task.completed). // 只获取任务名称 map((task) => task.name) /* 任务如下所示: task = { user_id : number, completed : boolean, name : string } */</code>
RXJS mempunyai pelbagai pengendali yang boleh digunakan untuk mengawal bagaimana aliran data antara objek dan pemerhati yang dapat dilihat. Beberapa pengendali utama termasuk peta (), penapis (), mengurangkan (), menggabungkan (), dan concat (). Setiap pengendali ini mengendalikan aliran data dengan cara yang berbeza, seperti menukar data, menapis nilai tertentu, atau menggabungkan pelbagai aliran.
rxjs menyediakan beberapa pengendali yang mengendalikan kesilapan, seperti catchError (), cuba semula (), dan retrywhen (). Pengendali penangkapan () digunakan untuk menangkap kesilapan pada aliran yang dapat dilihat dan mengembalikan objek baru yang dapat dilihat atau membuang kesilapan. Pengendali semula () boleh digunakan untuk menyerahkan semula objek yang boleh dilihat sekiranya berlaku ralat. Pengendali semula () adalah sama, tetapi ia memberikan lebih banyak kawalan ke atas apabila cuba semula.
Apabila anda melanggan yang dapat dilihat, anda menerima langganan yang mempunyai kaedah berhenti berlangganan (). Anda boleh memanggil kaedah ini untuk membatalkan pelaksanaan objek yang dapat dilihat dan membersihkan sebarang sumber yang sedang digunakan. Berikut adalah contoh:
<code class="language-javascript">const task_stream = parameter_stream. debounce(1000). map((parameter) => { getTasks(). retry(3). filter((task) => task.user_id === user_id). filter((task) => task.completed === parameter). map((task) => task.name) }). flatMap(Rx.Observable.from). distinctUntilChanged(). update()</code>
Dalam RXJS, objek yang dapat dilihat boleh menjadi panas atau sejuk. Pemantauan sejuk mula berjalan apabila dilanggan, sementara pemerhatian panas menghasilkan nilai walaupun sebelum melanggan. Dalam erti kata lain, objek yang dapat dilihat sejuk tidak aktif, manakala objek yang boleh dilihat panas tidak.
RXJS menyediakan beberapa pengendali yang menggabungkan pelbagai objek yang dapat dilihat, seperti gabungan (), concat (), combinelatest (), dan zip (). Setiap pengendali ini menggabungkan aliran data dengan cara yang berbeza, bergantung kepada keperluan khusus anda.
Topik dalam RXJS adalah jenis objek yang boleh dilihat khas yang membolehkan multicasting nilai kepada pelbagai pemerhati. Tidak seperti objek yang boleh dilihat biasa, topik mengekalkan pendaftaran untuk banyak pendengar.
Sudut menyokong RXJS dalam dibina dan menggunakannya secara dalaman untuk pelbagai fungsi. Anda juga boleh menggunakan RXJS dalam kod anda sendiri untuk mengendalikan operasi asynchronous dan melaksanakan fungsi seperti penyelesaian automatik, de-jitter, pendikit, pengundian, dll.
RXJS boleh digunakan dalam pelbagai senario di mana data tak segerak diperlukan. Beberapa kes penggunaan biasa termasuk mengendalikan input pengguna, membuat permintaan HTTP, menggunakan websocket, dan mengendalikan animasi.
Atas ialah kandungan terperinci 10 fungsi RXJS yang perlu diketahui dengan contoh. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!