flatMap을 사용해야하는 이유는 무엇입니까?


94

RxJS를 사용하기 시작했는데이 예제에서 왜 flatMap또는 같은 함수를 사용해야하는지 이해가 안됩니다 concatAll. 여기 배열 배열은 어디에 있습니까?

var requestStream = Rx.Observable.just('https://api.github.com/users');

var responseMetastream = requestStream
  .flatMap(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

responseMetastream.subscribe(url => {console.log(url)})

누군가가 무슨 일이 일어나고 있는지 시각적으로 설명 할 수 있다면 매우 도움이 될 것입니다.


1
이 답변은 제공되는 귀중한 참조 때문에 훌륭하지만 rxjs 용어는 영어로 잘 번역되지 않습니다. (사진이 더 좋습니다). 그래서 저는 이와 같은 간단한 예제 나 rxjs 리포지토리에서 더 복잡한 예제를 실행하고 플랫 맵 및 맵 연산자 앞뒤에 ".do"연산자를 추가 한 다음 Chrome 디버거로 중단 점을 설정하는 것이 좋습니다. 각각 다른 출력을 생성하는 것을 즉시 볼 수 있습니다.
HipsterZipster 2016-06-03

5
나는 경우 생각 flatMap명명되었을 것입니다 mapThenFlatten, 그것은 덜 혼동 될 것이다.
염소

답변:


73

제가보기 시작했을 때 저도 Rxjs그 돌을 발견했습니다. 나를 도운 것은 다음과 같습니다.

  • reactx.io의 문서. 예 flatMap: http://reactivex.io/documentation/operators/flatmap.html
  • rxmarbles의 설명서 : http://rxmarbles.com/ . 당신은 flatMap거기에서 찾을 수 없으며 , mergeMap대신 (다른 이름)을 보아야합니다 .
  • 누락 된 Rx 소개 : https://gist.github.com/staltz/868e7e9bc2a7b8c1f754 . 매우 유사한 예를 다룹니다. 특히 약속이 하나의 값만 방출하는 관찰 가능한 것과 유사하다는 사실을 다룹니다.
  • 마지막으로 RxJava의 유형 정보를 살펴 봅니다. 입력되지 않은 Javascript는 여기에서 도움이되지 않습니다. 기본적으로 Observable<T>T 유형의 값을 푸시하는 관찰 가능한 객체를 나타내는 경우 유형 flatMap의 함수를 T' -> Observable<T>인수로 취하고 Observable<T>. map유형의 기능을 소요 T' -> T하고 반환 Observable<T>.

    예제로 돌아 가면 URL 문자열에서 약속을 생성하는 함수가 있습니다. 그래서 T' : string,하고 T : promise. 그리고 어떤에서 우리는 이전 말했다 promise : Observable<T''>그래서, T : Observable<T''>함께 T'' : html. 약속을 생성하는 함수를에 넣으면 원하는 것이 : Observable이 값 을 방출하기를 원할 때 map얻을 수 있습니다. 에서 결과를 평평하게 (관찰 가능한 레이어를 제거)하기 때문에 이렇게 호출됩니다 . 배경에 따라 중국어가 될 수 있지만 http://reactivex.io/documentation/operators/flatmap.html 에서 정보를 입력하고 그림을 입력하면 모든 것이 명확 해졌습니다 .Observable<Observable<T''>>Observable<T''>htmlflatMapmap


2
난 당신이 간단하게 할 수 있어야한다고 언급하는 것을 잊었다 return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));return jQuery.getJSON(requestUrl);flatMap도 타입의 약속 즉, 기능을 반환하는 선택기 함수를 받아 들인다 T' -> Promise.
user3743222

2
와, GitHub Gist ( gist.github.com/staltz/868e7e9bc2a7b8c1f754 )는 정말 환상적입니다. RxJS와 같은 ReactiveX 라이브러리로 작업하는 모든 사람에게 권장합니다.
Jacob Stamm

@JacobStamm 동의합니다. 그냥 일을 더 쉽게 만듭니다.
CruelEngine

이 구문은 무엇을 의미 T’ -> T합니까? 나는 T일반적인 것으로 이해 하지만 아포스트로피와 지방이없는 화살표는 무엇입니까?
1252748

답의 의미를 변경하지 않고 T '를 X 또는 Y로 바꿀 수 있습니다. 화살표는 유형 서명에 대한 Haskell 표기법입니다. 따라서 T '-> T는 T'유형의 요소를 취하고 T 유형의 요소를 반환하는 함수의 시그니처입니다
user3743222

124
['a','b','c'].flatMap(function(e) {
    return [e, e+ 'x', e+ 'y',  e+ 'z'  ];
});
//['a', 'ax', 'ay', 'az', 'b', 'bx', 'by', 'bz', 'c', 'cx', 'cy', 'cz']


['a','b','c'].map(function(e) {
    return [e, e+ 'x', e+ 'y',  e+ 'z'  ];
});
//[Array[4], Array[4], Array[4]]

결과가 더 많은 Observable 인 Observable이있을 때 flatMap을 사용합니다.

다른 Observable에 의해 생성 된 Observable이있는 경우 데이터가 아닌 Observable이 있기 때문에 직접 필터링, 축소 또는 매핑 할 수 없습니다. 관찰 가능 항목을 생성하는 경우지도 위에 flatMap을 선택하십시오. 그럼 괜찮아요.

두 번째 스 니펫에서와 같이 비동기 작업을 수행하는 경우 flatMap을 사용해야합니다.

var source = Rx.Observable.interval(100).take(10).map(function(num){
    return num+1
});
source.subscribe(function(e){
    console.log(e)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.1/Rx.min.js"></script>

var source = Rx.Observable.interval(100).take(10).flatMap(function(num){
    return Rx.Observable.timer(100).map(() => num)
});
source.subscribe(function(e){
    console.log(e)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.1/Rx.min.js"></script>


33

사람들은 다음과 같은 정의를 제공함으로써 일을 지나치게 복잡하게 만드는 경향이 있습니다 .

flatMap은 Observable에 의해 방출 된 항목을 Observable로 변환 한 다음 이들의 방출을 단일 Observable로 평탄화합니다.

이 정의가 여전히 저를 혼란스럽게한다고 맹세하지만 예제를 사용하는 가장 간단한 방법으로 설명하겠습니다.

상황 : 다음과 같이 상황을 시각화 할 수 있도록 필요한 데이터를 포함하는 옵저버 블을 반환하는 HTTP 호출을 만드는 데 사용할 데이터 (단순 URL)를 반환하는 옵저버 블이 있습니다.

Observable 1
    |_
       Make Http Call Using Observable 1 Data (returns Observable_2)
            |_
               The Data We Need

보시다시피 필요한 데이터에 직접 도달 할 수 없으므로 데이터를 검색하는 첫 번째 방법은 다음과 같은 일반 구독을 사용할 수 있습니다.

Observable_1.subscribe((URL) => {
         Http.get(URL).subscribe((Data_We_Need) => {
                  console.log(Data_We_Need);
          });
});

이것은 작동하지만 보시다시피 데이터를 얻기 위해 구독을 중첩해야합니다. 이것은 현재 나쁘지 않지만 유지 관리 할 수없는 10 개의 중첩 구독이 있다고 가정합니다.

따라서이를 처리하는 더 좋은 방법 flatMap은 동일한 작업을 수행하지만 중첩 된 구독을 피하는 연산자를 사용 하는 것입니다.

Observable_1
    .flatMap(URL => Http.get(URL))
    .subscribe(Data_We_Need => console.log(Data_We_Need));

32

flatMap Observable에 의해 방출 된 항목을 새로운 Observable로 변환 한 다음 그 방출을 단일 Observable로 평평하게 만듭니다.

get("posts")의해 "평탄화 된"Observable을 반환하는 아래 시나리오를 확인하십시오 flatMap.

myObservable.map(e => get("posts")).subscribe(o => console.log(o));
// this would log Observable objects to console.  

myObservable.flatMap(e => get("posts")).subscribe(o => console.log(o));
// this would log posts to console.

2
멋지고 간단한 대답입니다. 이것이 최고라고 생각합니다.
vaughan

"flatMap은 Observable에 의해 방출 된 항목을 새로운 Observable로 변환 한 다음 그 방출을 단일 Observable로 평평하게 만듭니다." 이것은 훌륭한 물건입니다.
MBak

18

단순한:

[1,2,3].map(x => [x, x * 10])
// [[1, 10], [2, 20], [3, 30]]

[1,2,3].flatMap(x => [x, x * 10])
// [1, 10, 2, 20, 3, 30]]

16

배열의 배열이 아닙니다. observable (s)의 observable입니다.

다음은 관찰 가능한 문자열 스트림을 반환합니다.

requestStream
  .map(function(requestUrl) {
    return requestUrl;
  });

이것은 관찰 가능한 json 스트림의 관찰 가능한 스트림을 반환하지만

requestStream
  .map(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

flatMap observable을 자동으로 평면화하여 json 스트림을 직접 관찰 할 수 있습니다.


3
이 개념을 이해하기 어렵습니다. "관찰 가능한 json 스트림의 관찰 가능한 스트림을 반환합니다"라는 의미를 시각적으로 추가해 주시겠습니까? 감사.
user233232 2015

@ user233232, like [x, x, x, x] ~ [[xxx], [[xxx], [xxx]]]
serkan

첫 번째 문장을 이해하는 열쇠는 flatMap(및 map)이 배열에 특별하지 않다는 것을 이해하는 것입니다 . 배열, 사전, "옵션", 반응 스트림, 약속, 포인터, 심지어 함수 자체를 포함하여 모든 일반 컨테이너 또는 래퍼에서 이러한 작업을 정의 할 수 있습니다. 이것은 모나드라고 불리는 수학적 구조의 새로운 속성입니다. 위의 모든 예제는 모나드가되기위한 요구 사항을 충족하므로 모두 map및 a flatMap(일부주의 사항 포함)에 대한 정의가 제공 될 수 있습니다 .
mklbtz

14

구독을 사용하여 flatMap의 동등한 구현을 보여줍니다.

flatMap없이 :

this.searchField.valueChanges.debounceTime(400)
.subscribe(
  term => this.searchService.search(term)
  .subscribe( results => {
      console.log(results);  
      this.result = results;
    }
  );
);

flatMap 사용 :

this.searchField.valueChanges.debounceTime(400)
    .flatMap(term => this.searchService.search(term))
    .subscribe(results => {
      console.log(results);
      this.result = results;
    });

http://plnkr.co/edit/BHGmEcdS5eQGX703eRRE?p=preview

도움이 되었기를 바랍니다.

올리비에.


13

Observable은 다음, 오류 및 완료와 같은 이벤트 스트림을 생성하는 객체입니다.

함수가 Observable을 반환하면 스트림이 아니라 Observable의 인스턴스를 반환합니다. 그만큼flatMap운영자는 단순히 스트림에 해당 인스턴스를 매핑합니다.

다음 flatMap과 비교할 때 의 동작입니다 map. 주어진 함수를 실행하고 결과 개체를 스트림으로 평면화합니다.


7

flatMap 사용

var requestStream = Rx.Observable.just('https://api.github.com/users');

var responseMetastream = requestStream
  .flatMap(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

responseMetastream.subscribe(json => {console.log(json)})

flatMap없이

var requestStream = Rx.Observable.just('https://api.github.com/users');

var responseMetastream = requestStream
  .map(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

responseMetastream.subscribe(jsonStream => {
  jsonStream.subscribe(json => {console.log(json)})
})

0

flatMap은 Observable에 의해 방출 된 항목을 Observable로 변환 한 다음 이들의 방출을 단일 Observable로 평탄화합니다.

나는 바보가 아니지만 이것을 10 번 읽어야했지만 여전히 이해하지 못한다. 코드 스 니펫을 읽을 때 :

[1,2,3].map(x => [x, x * 10])
// [[1, 10], [2, 20], [3, 30]]

[1,2,3].flatMap(x => [x, x * 10])
// [1, 10, 2, 20, 3, 30]

그런 다음 무슨 일이 일어나고 있는지 이해할 수 있었고 두 가지를 수행합니다.

flatMap :

  1. map : *) 방출 된 항목을 Observable로 변환합니다.
  2. flat : 그런 다음 해당 Observable을 하나의 Observable로 병합합니다.

*) 변형 단어는 항목이 다른 것으로 변형 될 수 있다고 말합니다.

그런 다음 병합 연산자가 명확 해져 매핑없이 평면화를 수행합니다. 왜 그것을 mergeMap 이라고 부르지 않습니까 ? 이 별칭도 보인다 mergeMap을 위한 그 이름 flatMap .

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