rxJS의 파이프는 무엇입니까?


104

기본 컨셉이있는 것 같은데 모호한 부분이 있습니다

그래서 일반적으로 이것은 내가 관찰 가능한 것을 사용하는 방법입니다.

observable.subscribe(x => {

})

데이터를 필터링하려면 다음을 사용할 수 있습니다.

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

})

나는 또한 이것을 할 수있다 :

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

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

})

그래서 내 질문은 다음과 같습니다.

  1. 차이점은 무엇입니까?
  2. 차이가 없다면 함수 파이프가 존재하는 이유는 무엇입니까?
  3. 이러한 함수에 다른 가져 오기가 필요한 이유는 무엇입니까?

1
나는 그것이 네이티브가 아닌 맞춤형 운영자를위한 것이라고 말하려고했지만 그것이 옳은지조차 알지 못한다. 합니까는 pipe()당신이 만드는 것이 연산자를 통과하자?
zero298

답변:


69

"pipable"(이전의 "lettable") 연산자는 RxJS 5.5 이후 연산자를 사용 하는 현재 권장되는 방법 입니다.

공식 문서 https://rxjs.dev/guide/v6/pipeable-operators 를 읽는 것이 좋습니다.

주된 차이점은 사용자 지정 연산자를 만드는 것이 더 쉽고, Observable두 개의 다른 당사자가 같은 이름의 연산자를 만들려고 할 때 충돌을 일으킬 수있는 일부 전역 개체를 변경하지 않으면 서 트리 쉐이킹이 더 좋다는 것 입니다.

import각 연산자에 대해 별도의 문을 사용 'rxjs/add/operator/first'하는 것이 더 작은 앱 번들을 만드는 방법이었습니다. 전체 RxJS 라이브러리 대신 필요한 연산자 만 가져 오면 전체 번들 크기를 크게 줄일 수 있습니다. 그러나 컴파일러는 'rxjs/add/operator/first'코드에 실제로 필요하기 때문에 가져 왔는지 또는 코드를 리팩토링 할 때 제거하는 것을 잊었 는지 알 수 없습니다 . 이는 사용하지 않는 가져 오기가 자동으로 무시되는 pipable 연산자를 사용하는 장점 중 하나입니다.


1
귀하의 확인 unused imports are ignored automatically에 대해 현재 IDE에는 사용하지 않는 가져 오기를 제거하는 플러그인이 있습니다.
silvanasono

모든 사람이 이러한 IDE 또는 플러그인을 사용하는 것은 아니며 많은 사람들이 기본 텍스트 편집기를 사용합니다. 아마도 대부분의 경우 팀의 모든 구성원이 우리와 같은 IDE / 플러그인 집합 / 텍스트 편집기를 사용하고 있다는 진술을 전달할 수 없습니다.
Adam Faryna

3
@AdamFaryna 확실히, 일부 팀은 종이에 코드를 작성할 수도 있지만 최신 도구를 사용할 수 있다면 왜 그렇습니까? 특히 중요한 플러그인없이 텍스트 편집기를 사용하는 것은 종이에 코드를 작성하는 것과 유사합니다. 당신은 그렇게 할 수 있지만, 어떤 점잖은 팀 / 개발자는 할 이유
Denes PAPP

@DenesPapp 코드 편집기는 사람들이 생산적인 방식으로 사용할 수있는 한 중요하지 않습니다. 그 외에는 개인적인 취향 일뿐입니다. 종이에 코드를 작성하는 비유는 정확하지 않습니다. 종이에 코드를 실행할 수는 없지만 텍스트 편집기로 작성된 코드는 실행할 수 있습니다.
Adam Faryna

1
@perymimon 할 수 있지만 rxjs-compat패키지 github.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/v6/…
martin

16

파이프 방식

원본 문서에 따르면

pipable 연산자는 함수가 Observable 을 입력으로 취하고 다른 Observable을 반환한다는 것입니다.

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

원본 게시물

파이프는 무슨 뜻입니까?

즉, observable 인스턴스에서 이전에 사용한 모든 연산자는 다음에서 순수 함수로 사용할 수 있습니다. rxjs/operators . 이렇게하면 Observable을 확장하는 사용자 지정 관찰 가능 항목을 만든 다음 자신의 사용자 지정 항목을 만들기 위해 리프트를 덮어 써야하는 모든 종류의 프로그래밍 체조에 의존하지 않고도 연산자 구성을 구축하거나 연산자를 재사용 할 수 있습니다.

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는 코드를 변경하고 속성을 제공했습니다. 불편을 끼쳐 드려 죄송합니다.
Chanaka Weerasinghe

감사합니다. 파이프 가능 연산자를 함수 참조로 저장하고 pipe () 호출에서 사용할 수 있다는 사실조차 몰랐습니다. 항상 인라인으로 수행하는 것보다 훨씬 깨끗합니다.
알렉스. A

10

내가 생각 해낸 좋은 요약은 다음과 같습니다.

스트리밍 작업 (맵, 필터, 축소 ...)을 핵심 기능 (구독, 파이핑)에서 분리합니다. 체인 대신 파이핑 작업을 수행하면 Observable의 프로토 타입을 오염시키지 않으므로 트리 쉐이킹을 더 쉽게 수행 할 수 있습니다.

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

점 체인을위한 패치 된 연산자의 문제점은 다음과 같습니다.

패치 연산자를 가져 오는 모든 라이브러리는 해당 라이브러리의 모든 소비자에 대해 Observable.prototype을 증가시켜 블라인드 종속성을 만듭니다. 도서관이 그들의 사용을 제거하면 무의식적으로 다른 모든 사람들을 망가 뜨립니다. pipeables를 사용하면 필요한 연산자를 사용하는 각 파일로 가져와야합니다.

프로토 타입에 직접 패치 된 운영자는 롤업 또는 웹팩과 같은 도구에 의해 "트리 쉐이크 가능"하지 않습니다. 파이프 가능한 연산자는 모듈에서 직접 끌어온 함수일뿐입니다.

앱에서 가져 오는 사용되지 않는 연산자는 어떤 종류의 빌드 도구 나 Lint 규칙으로도 안정적으로 감지 할 수 없습니다. 즉, 스캔을 가져올 수 있지만 사용을 중지해도 여전히 출력 번들에 추가됩니다. 파이프 가능 연산자를 사용하면 사용하지 않는 경우 린트 규칙으로 선택할 수 있습니다.

기능적 구성은 굉장합니다. 사용자 지정 연산자를 빌드하는 것이 훨씬 더 쉬워졌고 이제는 rxjs의 다른 모든 연산자처럼 작동하고 보입니다. 더 이상 Observable을 확장하거나 리프트를 재정의 할 필요가 없습니다.


9

차이점은 무엇입니까? 예제에서 볼 수 있듯이 주요 차이점은 소스 코드의 가독성을 향상시키는 것입니다. 귀하의 예제에는 두 개의 함수 만 있지만 수십 개의 함수가 있다고 상상해보십시오. 그러면 그것은 같이 갈 것입니다

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

특히 함수 내부를 채울 때 정말 추하고 읽기 어렵습니다. 또한 Visual Studio 코드와 같은 특정 편집기는 140 줄 이상을 허용하지 않습니다. 그러나 다음과 같이 진행되면.

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

이것은 가독성을 대폭 향상시킵니다.

차이가 없다면 함수 파이프가 존재하는 이유는 무엇입니까? PIPE () 함수의 목적은 옵저버 블 을 가져오고 반환하는 모든 함수를 하나로 묶는 것입니다. 처음에는 observable을 취하고, 그 observable은 내부에 사용 된 각 함수에 의해 pipe () 함수 전체에서 사용됩니다.

첫 번째 함수는 관찰 가능 항목을 가져 와서 처리하고, 값을 수정하고, 다음 함수로 전달합니다. 다음 함수는 첫 번째 함수의 관찰 가능 항목을 가져 와서 처리하고 다음 함수로 전달한 다음 모든 함수가 끝날 때까지 계속됩니다. pipe () 함수 내부에서 Observable을 사용하면 마지막으로 처리 된 Observable이 있습니다. 마지막에 subscribe () 함수로 Observable을 실행하여 값을 추출 할 수 있습니다. 원래 Observable의 값은 변경되지 않습니다. !! 

이러한 함수에 다른 가져 오기가 필요한 이유는 무엇입니까? 가져 오기는 rxjs 패키지에서 함수가 지정된 위치에 따라 다릅니다. 이렇게됩니다. 모든 모듈은 Angular의 node_modules 폴더에 저장됩니다. "모듈"에서 {클래스} 가져 오기;

다음 코드를 예로 들어 보겠습니다. 방금 stackblitz에 썼습니다. 따라서 자동으로 생성되거나 다른 곳에서 복사되는 것은 없습니다. 나는 당신이 가서 읽을 수있을 때 rxjs 문서에 명시된 것을 복사하는 요점을 보지 못합니다. 문서를 이해하지 못했기 때문에 여기서이 질문을했다고 가정합니다. 

  • 파이프, 관찰 가능한, 각 모듈에서 가져온 맵 클래스가 있습니다. 
  • 클래스 본문에서 코드에 표시된대로 Pipe () 함수를 사용했습니다. 
  • Of () 함수는 구독 할 때 순서대로 숫자를 방출하는 Observable을 반환합니다.

  • Observable은 아직 구독하지 않았습니다.

  • Observable.pipe ()와 같이 사용했을 때 pipe () 함수는 주어진 Observable을 입력으로 사용합니다.

  • 첫 번째 함수 인 map () 함수는 해당 Observable을 사용하여 처리하고 처리 된 Observable을 다시 pipe () 함수로 반환합니다.

  • 처리 된 Observable이 있다면 다음 함수에 주어집니다.

  • 모든 함수가 Observable을 처리 할 때까지 계속됩니다.

  • 끝에서 Observable은 pipe () 함수에 의해 변수로 반환되며 다음 예제에서는 obs입니다.

이제 Observable의 것은 옵저버가 구독하지 않는 한 어떠한 값도 방출하지 않는다는 것입니다. 그래서 subscribe () 함수를 사용하여이 Observable을 구독하고 구독하자마자 사용했습니다. of () 함수는 값을 방출하기 시작하고 pipe () 함수를 통해 처리되고 최종 결과를 얻습니다. 예를 들어 1은 of () 함수에서 가져오고 1은 map () 함수에서 1을 더합니다. 돌아왔다. subscribe (function ( argument ) {}) 함수 내에서 해당 값을 인수로 가져올 수 있습니다 .

인쇄하려면 다음과 같이 사용하십시오.

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.