angular - Na čo slúži pipe v RxJS?


Myslím, že mám základný koncept, ale sú tu niektoré nejasnosti

Takže všeobecne to je spôsob, ako používam Observable:

observable.subscribe(x => {

})

Ak chcem filtrovať dáta, môžem použiť toto:

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

})

Toto môžem tiež urobiť:

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

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

})

Takže moje otázky sú:

  1. Aký je rozdiel?
  2. Ak nie je žiadny rozdiel, prečo funkcia pipe existuje?
  3. Prečo tieto funkcie potrebujú rôzne importy?

Odpoveď č. 1

Operátory „pipeable“ (predtým „lettable“) sú aktuálny a odporúčaný spôsob používania operátorov od RxJS 5.5.

Dôrazne vám odporúčam prečítať si oficiálnu dokumentáciu o prenosných operátorch

Hlavný rozdiel je v tom, že je jednoduchšie vytvárať vlastných operátorov a že je lepšie treeshakovateľný, pričom nemení žiadny globálny objekt Observable, ktorý by mohol spôsobiť kolízie, ak by dve rôzne strany chceli vytvoriť operátor s rovnakým menom.

Používanie samostatného import príkazu pre každý operátor 'rxjs/add/operator/first' bolo spôsobom, ako vytvoriť menšie balíky aplikácie. Importovaním iba operátorov, ktoré potrebujete, namiesto celej knižnice RxJS, môžete výrazne znížiť celkovú veľkosť balíka. Kompilátor však nevie, či ste importovali 'rxjs/add/operator/first', pretože ho skutočne potrebujete vo svojom kóde, alebo ste ho len zabudli odstrániť pri refaktorovaní kódu. To je jedna z výhod používania operátorov typu pipeable, kde sú nepoužité importy automaticky ignorované.

Odpoveď č. 2

Metóda potrubia

Podľa pôvodnej dokumentácie je operátor pipeable funkcia, ktorá prijíma observables ako vstup a vracia ďalší observable. Predchádzajúci observable zostáva nezmenený.

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

Pôvodný príspevok

Čo znamená pipe?

To znamená, že všetky operátory, ktoré ste predtým používali na inštancii observable, sú dostupné ako čisté funkcie pod rxjs/operators. To veľmi uľahčuje zostavovanie kompozície operátorov alebo opätovné použitie operátorov, bez toho, aby ste sa museli uchýliť k rôznym programátorským gymnastikám, kde musíte vytvoriť vlastný observable rozširujúci Observable a potom prepísať lift len aby ste vytvorili vlastnú vlastnú vec.

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

Odpoveď č. 3

Aký je rozdiel? Ako vidíte vo vašom príklade, hlavným rozdielom je zlepšiť čitateľnosť zdrojového kódu. Vo vašom príklade sú len dve funkcie, ale predstavte si, keby tam bolo tucet funkcií? Potom to pôjde takto

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

Je to naozaj čoraz škaredšie a ťažko čitateľné, najmä keď vypĺňate obsah vo funkciách. Navyše niektoré editory, ako napríklad Visual Studio Code, neumožňujú riadky dlhšie ako 140 znakov. Ale ak to pôjde nasledovne.

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

Toto drasticky zlepšuje čitateľnosť.

Ak nie je žiadny rozdiel, prečo funkcia pipe existuje? Účelom funkcie PIPE() je zoskupiť všetky funkcie, ktoré prijímajú a vracajú observable. Najprv prijme observable a potom sa tento observable používa po celú dobu v rámci funkcie pipe() každou funkciou, ktorá je v nej použitá.

Prvá funkcia vezme pozorovateľný objekt, spracuje ho, upraví jeho hodnotu a odovzdá ďalšej funkcii, potom ďalšia funkcia vezme výstupný pozorovateľný objekt prvej funkcie, spracuje ho a odovzdá ďalšej funkcii, potom to pokračuje, až kým všetky funkcie vo funkcii pipe() nepoužijú tento pozorovateľný objekt, nakoniec máte spracovaný pozorovateľný objekt. Na konci môžete vykonať pozorovateľný objekt pomocou funkcie subscribe(), aby ste z neho získali hodnotu. Pamätajte, že hodnoty v pôvodnom pozorovateľnom objekte sa nezmenia.

Prečo tieto funkcie potrebujú rôzne importy? Importy závisia od toho, kde je funkcia špecifikovaná v balíku rxjs. Ide to takto. Všetky moduly sú uložené v priečinku node_modules v Angulari. import { trieda } z "modulu";

Vezmime si nasledujúci kód ako príklad. Práve som ho napísal v stackblitz. Takže nič nie je automaticky generované ani skopírované odniekiaľ inde. Nevidím dôvod kopírovať to, čo je uvedené v dokumentácii rxjs, keď si to môžete ísť prečítať sami. Predpokladám, že ste túto otázku položili tu, pretože ste nerozumeli dokumentácii.

  • Zo zodpovedajúcich modulov sú importované triedy pipe, observable, of a map.
  • V tele triedy som použil funkciu Pipe(), ako je vidieť v kóde.
  • Funkcia Of() vracia observable, ktorý vysiela čísla v poradí, keď je prihlásený.

  • Observable ešte nie je prihlásený na odber.

  • Keď ste ho používali ako Observable.pipe(), funkcia pipe() používa daný Observable ako vstup.

  • Prvá funkcia, funkcia map(), používa ten Observable, spracuje ho, a vráti spracovaný Observable späť do funkcie pipe()

  • potom sa tento spracovaný Observable odovzdá nasledujúcej funkcii, ak nejaká existuje,

  • a pokračuje to takto, kým všetky funkcie nespracujú Observable,

  • na konci je tento Observable vrátený funkciou pipe() do premennej, v nasledujúcom príklade je to obs.

Teraz vec na Observable je taká, že pokiaľ sa pozorovateľ na ňu neprihlási, nevydáva žiadnu hodnotu. Takže som použil funkciu subscribe(), aby som sa prihlásil na tento Observable, a hneď ako som sa prihlásil. Funkcia of() začne vydávať hodnoty, tie sa potom spracujú cez funkciu pipe(), a na konci dostanete konečný výsledok, napríklad 1 je získané z funkcie of(), 1 sa pripočíta v funkcii map() a vráti sa späť. Túto hodnotu môžete získať ako argument vo funkcii subscribe(function(argument) {} ).

Ak to chceš vytlačiť, potom používaj ako

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

Odpoveď č. 4

Dobrý súhrn, ktorý som vytvoril, je:

Oddeľuje streamingové operácie (map, filter, reduce...) od jadrovej funkcionality (prihlasovanie, prepájanie). Tým, že sa operácie prepájajú namiesto reťazenia, neznečisťuje sa prototyp Observable, čo uľahčuje tree shaking.

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

Problémy s opravenými operátormi pre reťazenie cez bodku sú:

Každá knižnica, ktorá importuje patch operátor, rozšíri Observable.prototype pre všetkých používateľov tejto knižnice, čím vzniknú neviditeľné závislosti. Ak knižnica odstráni ich používanie, nevie, že poškodí ostatných. Pri pipeables musíte importovať operátory, ktoré potrebujete, do každého súboru, v ktorom ich používate.

Operátory, ktoré sú priamo zapatchované na prototype, nie sú „optimalizovateľné“ nástrojmi ako rollup alebo webpack. Rúrkové operátory budú, pretože sú len funkciami načítavanými priamo z modulov.

Nepoužívaní operátori, ktorí sú importovaní v aplikáciách, nemôžu byť spoľahlivo detekovaní žiadnym nástrojom na zostavovanie ani pravidlom lintu. To znamená, že môžete importovať scan, ale prestať ho používať, a stále bude pridaný do vášho výstupného balíka. Pri použiteľných operátoroch, ak ich nepoužívate, pravidlo lintu ich môže za vás zachytiť.

Funkcionálna kompozícia je úžasná. Vytváranie vlastných vlastných operátorov sa stáva oveľa, oveľa jednoduchšie, a teraz fungujú a vyzerajú presne ako všetky ostatné operátory z rxjs. Už nemusíte rozširovať Observable ani prepisovať lift.

Súvisiace články