angular - Čemu služi pipe u RxJS-u?


Mislim da imam osnovni koncept, ali postoje neke nejasnoće

Dakle, općenito, ovako koristim Observable:

observable.subscribe(x => {

})

Ako želim filtrirati podatke, mogu koristiti ovo:

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

})

Također mogu ovo učiniti:

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

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

})

Dakle, moja pitanja su:

  1. Koja je razlika?
  2. Ako nema razlike, zašto funkcija pipe postoji?
  3. Zašto tim funkcijama trebaju različiti uvozi?

Odgovor #1

Operateri „pipeable“ (ranije „lettable“) su trenutni i preporučeni način korištenja operatora od RxJS 5.5.

Toplo vam preporučujem da pročitate službenu dokumentaciju o operatorima koji se mogu povezivati

Glavna razlika je u tome što je lakše napraviti prilagođene operatore i što je bolje za treeshaking, a da se ne mijenja neki globalni Observable objekt koji bi mogao uzrokovati sukobe ako dvije različite strane žele stvoriti operator istog imena.

Korištenje zasebne import izjave za svaki operator 'rxjs/add/operator/first' bio je način za izradu manjih aplikacijskih paketa. Uvozom samo onih operatora koji su vam potrebni umjesto cijele RxJS biblioteke možete značajno smanjiti ukupnu veličinu paketa. Međutim, kompajler ne može znati jeste li uvezli 'rxjs/add/operator/first' zato što ga stvarno trebate u svom kodu ili ste ga jednostavno zaboravili ukloniti prilikom refaktoriranja koda. To je jedna od prednosti korištenja pipeable operatora gdje se neiskorišteni uvozi automatski ignoriraju.

Odgovor #2

Metoda cijevi

Prema originalnoj dokumentaciji, operater koji se može koristiti u lancu je funkcija koja prima observables kao ulaz i vraća drugi observable. Prethodni observable ostaje nepromijenjen.

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

Originalna objava

Što znači cijev?

To znači da su svi operatori koje ste prethodno koristili na instanci observabla dostupni kao čiste funkcije unutar rxjs/operators. To olakšava izgradnju kompozicije operatora ili ponovnu upotrebu operatora, bez potrebe da pribjegavate raznim programerskim gimnastikama gdje morate kreirati prilagođeni observable koji nasljeđuje Observable, a zatim prepisati lift samo da biste napravili vlastitu prilagođenu stvar.

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

Odgovor #3

Koja je razlika? Kao što vidite u vašem primjeru, glavna razlika je poboljšati čitljivost izvornog koda. U vašem primjeru postoje samo dvije funkcije, ali zamislite da ima na desetke funkcija? tada će ići ovako

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

Stvarno postaje ružno i teško za čitanje, posebno kada popunjavaš unutar funkcija. Osim toga, određeni uređivači poput Visual Studio Code-a ne dopuštaju duljinu linije veću od 140 znakova. Ali ako ide ovako.

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

Ovo dramatično poboljšava čitljivost.

Ako nema razlike, zašto uopće postoji funkcija pipe? Svrha funkcije PIPE() je spojiti zajedno sve funkcije koje uzimaju i vraćaju observable. Ona prvo uzima observable, a zatim se taj observable koristi kroz cijelu funkciju pipe() od strane svake funkcije koja se koristi unutar nje.

Prva funkcija uzima observable, obrađuje ga, modificira njegovu vrijednost i prosljeđuje sljedećoj funkciji, zatim sljedeća funkcija uzima izlazni observable prve funkcije, obrađuje ga i prosljeđuje sljedećoj funkciji, i tako se nastavlja dok sve funkcije unutar funkcije pipe() ne koriste taj observable, na kraju imate obrađeni observable. Na kraju možete izvršiti observable s funkcijom subscribe() kako biste iz njega izvukli vrijednost. Zapamtite, vrijednosti u izvornom observableu se ne mijenjaju.!!

Zašto te funkcije trebaju različite uvoze? Uvozi ovise o tome gdje je funkcija specificirana u rxjs paketu. Ide ovako. Svi su moduli pohranjeni u mapi node_modules u Angularu. import { class } from "module";

Uzmimo sljedeći kod kao primjer. Upravo sam ga napisao u stackblitzu. Dakle, ništa nije automatski generirano niti kopirano odnekud. Ne vidim poantu kopiranja onoga što je navedeno u rxjs dokumentaciji kada to možete i sami pročitati. Pretpostavljam da ste ovo pitanje postavili ovdje jer niste razumjeli dokumentaciju.

  • Postoje klase pipe, observable, of, map uvezene iz odgovarajućih modula.
  • U tijelu klase koristio sam funkciju Pipe(), kao što je prikazano u kodu.
  • Funkcija Of() vraća observable koji emitira brojeve u nizu kada je na njega pretplaćeno.

  • Observable još nije pretplaćen.

  • Kada ste ga koristili kao Observable.pipe(), funkcija pipe() koristi dani Observable kao ulaz.

  • Prva funkcija, funkcija map() koristi taj Observable, obrađuje ga i vraća obrađeni Observable natrag funkciji pipe()

  • tada se taj obrađeni Observable prosljeđuje sljedećoj funkciji, ako je ima,

  • i to tako ide dok sve funkcije ne obrade Observable,

  • na kraju se taj Observable vraća funkcijom pipe() u varijablu, u sljedećem primjeru u njegovu obs.

Sada stvar u Observableu je, sve dok promatrač nije pretplaćen na njega, on ne emitira nikakvu vrijednost. Dakle, koristio sam funkciju subscribe() da se pretplatim na ovaj Observable, a čim sam se pretplatio, funkcija of() počinje emitirati vrijednosti, zatim se one obrađuju kroz funkciju pipe(), i na kraju dobivate konačni rezultat, na primjer 1 se uzima iz funkcije of(), 1 se dodaje 1 u funkciji map(), i vraća natrag. Tu vrijednost možete dobiti kao argument unutar funkcije subscribe( function (argument) {} ).

Ako to želite ispisati, tada koristite kao

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

Odgovor #4

Dobar sažetak koji sam smislio je:

Odvaja streaming operacije (map, filter, reduce...) od osnovne funkcionalnosti (pretplata, spajanje cjevovoda). Korištenjem spajanja operacija umjesto lančanog povezivanja, ne onečišćuje se prototip Observablea, što olakšava izvođenje tree shakinga.

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

Problemi s popravljenim operatorima za lančano pozivanje su:

Bilo koja biblioteka koja uvozi operator zakrpe proširit će Observable.prototype za sve korisnike te biblioteke, stvarajući slijepa ovisnosti. Ako biblioteka ukloni njihovu upotrebu, nenamjerno će pokvariti sve ostale. S pipeables, morate uvesti operatore koje trebate u svaku datoteku u kojoj ih koristite.

Operatori koji su direktno dodani na prototip nisu „shakeable“ od alata poput rollupa ili webpacka. Pipeable operatori bit će shakeable jer su jednostavno funkcije uvezene iz modula.

Neiskorišteni operatori koji se uvoze u aplikacije ne mogu se pouzdano otkriti pomoću bilo kojeg alata za izgradnju ili pravila lintera. To znači da možda uvozite scan, ali prestanete ga koristiti, a on se i dalje dodaje u vaš izlazni paket. S pipeable operatorima, ako ga ne koristite, pravilo lintera može to otkriti umjesto vas.

Funkcionalna kompozicija je sjajna. Izrada vlastitih prilagođenih operatora postaje mnogo, mnogo lakša, i sada rade i izgledaju točno kao svi ostali operatori iz rxjs-a. Više ne trebate proširivati Observable niti nadjačavati lift.

Povezani članci