Untuk apa pipa di rxJS


110

Saya pikir saya memiliki konsep dasar, tetapi ada beberapa ketidakjelasan

Jadi secara umum inilah cara saya menggunakan observable:

observable.subscribe(x => {

})

Jika saya ingin memfilter data, saya dapat menggunakan ini:

import { first, last, map, reduce, find, skipWhile } from 'rxjs/operators';
observable.pipe(
    map(x => {return x}),
    first()
    ).subscribe(x => {

})

Saya juga bisa melakukan ini:

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/first';

observable.map(x => {return x}).first().subscribe(x => {

})

Jadi pertanyaan saya adalah:

  1. Apa bedanya?
  2. Jika tidak ada perbedaan, mengapa pipa fungsi ada?
  3. Mengapa fungsi tersebut membutuhkan impor yang berbeda?

1
Saya hendak mengatakan bahwa itu untuk operator khusus, non-asli, tetapi saya bahkan tidak tahu apakah itu benar. Apakah pipe()mengizinkan Anda melewati operator yang Anda buat?
nol298

Jawaban:


73

Operator "pipable" (sebelumnya "lettable") adalah cara saat ini dan yang direkomendasikan untuk menggunakan operator sejak RxJS 5.5.

Saya sangat menyarankan Anda untuk membaca dokumentasi resmi https://rxjs.dev/guide/v6/pipeable-operators

Perbedaan utamanya adalah lebih mudah membuat operator khusus dan lebih baik jika tidak mengubah beberapa Observableobjek global yang dapat menyebabkan benturan jika dua pihak berbeda ingin membuat operator dengan nama yang sama.

Menggunakan importpernyataan terpisah untuk setiap operator 'rxjs/add/operator/first'adalah cara untuk membuat bundel aplikasi yang lebih kecil. Dengan hanya mengimpor operator yang Anda perlukan, bukan seluruh pustaka RxJS, Anda dapat mengurangi ukuran paket total secara signifikan. Namun kompilator tidak dapat mengetahui apakah Anda mengimpor 'rxjs/add/operator/first'karena Anda benar-benar membutuhkannya dalam kode Anda atau Anda hanya lupa untuk menghapusnya saat merefaktor kode Anda. Itulah salah satu keuntungan menggunakan operator pipable di mana impor yang tidak terpakai akan diabaikan secara otomatis.


1
Tentang penegasan Anda unused imports are ignored automatically, saat ini IDE memiliki plugin yang menghapus impor yang tidak digunakan.
silvanasono

Tidak semua orang menggunakan IDE atau plugin ini, banyak orang menggunakan editor teks dasar. Mungkin sebagian besar waktu kami tidak dapat menyampaikan pernyataan bahwa setiap orang di tim menggunakan IDE / plugin set / editor teks yang sama seperti kami.
Adam Faryna

3
@AdamFaryna yakin, beberapa tim juga dapat menulis kode di atas kertas, tetapi mengapa mereka harus jika mereka memiliki alat modern yang tersedia? Menggunakan editor teks, apalagi tanpa plugin penting mirip dengan menulis kode di atas kertas. Anda dapat melakukan itu tetapi mengapa tim / pengembang yang layak melakukan itu
Denes Papp

Editor kode @DenesPapp tidak masalah selama orang dapat menggunakannya dengan cara yang produktif. Selain itu, itu hanya preferensi pribadi. Analogi Anda untuk menulis kode di atas kertas tidak akurat, Anda tidak dapat mengeksekusi kode di atas kertas tetapi kode yang ditulis di editor teks mana pun dapat dijalankan.
Adam Faryna

1
@perymimon Anda bisa tetapi Anda harus menginstal rxjs-compatpaket github.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/v6/…
martin

16

Metode pipa

Menurut Dokumentasi asli

operator pipable adalah fungsi yang mengambil observable sebagai input dan mengembalikan observable .previous observable lainnya tetap tidak dimodifikasi.

pipe(...fns: UnaryFunction<any, any>[]): UnaryFunction<any, any>

Posting Asli

Arti pipa apa?

Itu berarti bahwa setiap operator yang sebelumnya Anda gunakan pada instance observable tersedia sebagai fungsi murni di bawah rxjs/operators. Hal ini membuat pembuatan komposisi operator atau menggunakan kembali operator menjadi sangat mudah, tanpa harus menggunakan semua jenis pemrograman senam di mana Anda harus membuat Observable yang dapat diamati secara khusus, kemudian menimpa lift hanya untuk membuat barang kustom Anda sendiri.

const { Observable } = require('rxjs/Rx')
const { filter, map, reduce,  } = require('rxjs/operators')
const { pipe } = require('rxjs/Rx')

const filterOutWithEvens = filter(x => x % 2)
const doubleByValue = x => map(value => value * x);
const sumValue = reduce((acc, next) => acc + next, 0);
const source$ = Observable.range(0, 10)

source$.pipe(
  filterOutWithEvens, 
  doubleByValue(2), 
  sumValue)
  .subscribe(console.log); // 50

@VladKuts mengubah kode dan atribut yang diberikan. Maaf atas ketidaknyamanan ini.
Chanaka Weerasinghe

Terima kasih, saya bahkan tidak menyadari bahwa saya dapat menyimpan operator yang dapat menggunakan pipa sebagai referensi fungsi dan menggunakannya dalam panggilan pipe (). Itu jauh lebih bersih daripada selalu melakukannya secara inline.
Alex. Sebuah

10

Ringkasan bagus yang saya dapatkan adalah:

Ini memisahkan operasi streaming (peta, filter, kurangi ...) dari fungsionalitas inti (berlangganan, perpipaan). Dengan operasi pemipaan alih-alih rantai, itu tidak mencemari prototipe Observable sehingga lebih mudah untuk melakukan pengocokan pohon.

Lihat https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md#why

Masalah dengan operator yang ditambal untuk dot-chaining adalah:

Pustaka apa pun yang mengimpor operator patch akan menambah Observable.prototype untuk semua konsumen pustaka itu, menciptakan dependensi buta. Jika perpustakaan menghapus penggunaannya, tanpa disadari mereka merusak orang lain. Dengan pipa, Anda harus mengimpor operator yang Anda perlukan ke dalam setiap file tempat Anda menggunakannya.

Operator yang ditambal langsung ke prototipe tidak "dapat digoyahkan oleh pohon" oleh alat seperti rollup atau webpack. Operator pipa akan menjadi seperti fungsi yang ditarik dari modul secara langsung.

Operator yang tidak digunakan yang sedang diimpor dalam aplikasi tidak dapat dideteksi dengan andal oleh segala jenis alat build atau aturan lint. Itu berarti Anda dapat mengimpor pindaian, tetapi berhenti menggunakannya, dan pemindaian itu masih ditambahkan ke bundel keluaran Anda. Dengan operator yang dapat dialirkan pipa, jika Anda tidak menggunakannya, aturan lint dapat mengambilnya untuk Anda.

Komposisi fungsionalnya luar biasa. Membangun operator khusus Anda sendiri menjadi jauh lebih mudah, dan sekarang mereka berfungsi dan terlihat seperti semua operator lain dari rxjs. Anda tidak perlu memperpanjang Observable atau mengganti lift lagi.


9

Apa bedanya? Seperti yang Anda lihat dalam contoh Anda, perbedaan utamanya adalah meningkatkan keterbacaan kode sumber. Hanya ada dua fungsi dalam contoh Anda, tetapi bayangkan jika ada selusin fungsi? maka akan seperti itu

function1().function2().function3().function4()

itu benar-benar menjadi jelek, dan sulit untuk dibaca, terutama ketika Anda mengisi di dalam fungsi. Selain itu editor tertentu seperti kode Visual Studio tidak mengizinkan lebih dari 140 panjang baris. tetapi jika seperti berikut.

Observable.pipe(
function1(),
function2(),
function3(),
function4()
)

Ini secara drastis meningkatkan keterbacaan.

Jika tidak ada perbedaan, mengapa pipa fungsi ada? Tujuan dari fungsi PIPE () adalah untuk menggabungkan semua fungsi yang mengambil, dan mengembalikan yang dapat diamati. Ini mengambil observable pada awalnya, kemudian observable tersebut digunakan di seluruh fungsi pipe () oleh setiap fungsi yang digunakan di dalamnya.

Fungsi pertama mengambil yang dapat diamati, memprosesnya, mengubah nilainya, dan meneruskan ke fungsi berikutnya, kemudian fungsi berikutnya mengambil keluaran yang dapat diamati dari fungsi pertama, memprosesnya, dan meneruskan ke fungsi berikutnya, kemudian berlanjut hingga semua fungsi di dalam fungsi pipa () gunakan yang dapat diamati, akhirnya Anda memiliki pengamatan yang diproses. Pada akhirnya Anda dapat menjalankan fungsi observable dengan subscribe () untuk mengekstrak nilainya. Ingat, nilai dalam pengamatan asli tidak berubah. !! 

Mengapa fungsi tersebut membutuhkan impor yang berbeda? Impor bergantung pada tempat fungsi ditentukan dalam paket rxjs. Ini berjalan seperti ini. Semua modul disimpan dalam folder node_modules di Angular. impor {class} dari "modul";

Mari kita ambil kode berikut sebagai contoh. Saya baru saja menulisnya di stackblitz. Jadi tidak ada yang dibuat secara otomatis, atau disalin dari tempat lain. Saya tidak melihat gunanya menyalin apa yang dinyatakan dalam dokumentasi rxjs ketika Anda dapat pergi dan membacanya juga. Saya berasumsi bahwa Anda menanyakan pertanyaan ini di sini, karena Anda tidak memahami dokumentasinya. 

  • Ada pipa, dapat diamati, dari, kelas peta yang diimpor dari modul masing-masing. 
  • Di tubuh kelas, saya menggunakan fungsi Pipe () seperti yang terlihat pada kode. 
  • Fungsi Of () mengembalikan observable, yang memancarkan angka secara berurutan saat berlangganan.

  • Observable belum berlangganan.

  • Ketika Anda menggunakannya seperti Observable.pipe (), fungsi pipe () menggunakan Observable yang diberikan sebagai input.

  • Fungsi pertama, fungsi map () menggunakan Observable itu, memprosesnya, mengembalikan fungsi Observable yang diproses kembali ke pipe (),

  • maka Observable yang telah diproses tersebut diberikan ke fungsi selanjutnya jika ada,

  • dan terus berlanjut hingga semua fungsi memproses Observable,

  • pada akhirnya Observable dikembalikan oleh fungsi pipe () ke variabel, dalam contoh berikut obs.

Sekarang hal di Observable adalah, Selama pengamat tidak berlangganan, itu tidak memancarkan nilai apa pun. Jadi saya menggunakan fungsi subscribe () untuk berlangganan Observable ini, lalu segera setelah saya berlangganan. Fungsi of () mulai memancarkan nilai, kemudian diproses melalui fungsi pipa (), dan Anda mendapatkan hasil akhir di bagian akhir, misalnya 1 diambil dari fungsi (), 1 ditambahkan 1 pada fungsi map (), dan kembali. Anda bisa mendapatkan nilai itu sebagai argumen di dalam fungsi subscribe (fungsi ( argumen ) {}).

Jika Anda ingin mencetaknya, gunakan sebagai

subscribe( function (argument) {
    console.log(argument)
   } 
)
    import { Component, OnInit } from '@angular/core';
    import { pipe } from 'rxjs';
    import { Observable, of } from 'rxjs';
    import { map } from 'rxjs/operators';
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: [ './app.component.css' ]
    })
    export class AppComponent implements OnInit  {
    
      obs = of(1,2,3).pipe(
      map(x => x + 1),
      ); 
    
      constructor() { }
    
      ngOnInit(){  
        this.obs.subscribe(value => console.log(value))
      }
    }

https://stackblitz.com/edit/angular-ivy-plifkg

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.