Почему мы должны использовать flatMap?


Я начинаю использовать 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)})

Если кто-то может наглядно объяснить, что происходит, это будет очень полезно.

9 55

9 ответов:

когда я начал смотреть на Rxjs Я тоже наткнулся на этот камень. Мне помогло следующее:

  • документация от reactivex.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. если вы поместите эту функцию производства обещаний в map вы получаете Observable<Observable<T''>> если ты хочешь Observable<T''>: вы хотите, чтобы наблюдаемое излучало html значения. flatMap называется как это потому, что он сглаживает (удаляет наблюдаемый слой) результат от map. В зависимости от вашего фона, это может быть китайский для вас, но все стало кристально ясно для меня с вводом информации и рисунка отсюда : http://reactivex.io/documentation/operators/flatmap.html.

['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]]

вы используете flatMap, когда у вас есть наблюдаемый, результаты которого более заметны.

если у вас есть наблюдаемое, которое создается другим наблюдаемым, вы не можете фильтровать, уменьшать или сопоставлять его напрямую, потому что у вас есть наблюдаемые не данные. Если вы создаете наблюдаемый выбор 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>

flatMap преобразует элементы, испускаемые наблюдаемым в новые наблюдаемые, а затем сглаживает выбросы от них в один наблюдаемый.

Проверьте сценарий ниже, где get("posts") возвращает наблюдаемое, которое "сплющено" с помощью 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.

Это не массив массивов. Это наблюдаемое из наблюдаемых(ов).

следующее возвращает наблюдаемый поток строки.

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

В то время как это возвращает наблюдаемый поток наблюдаемого потока json

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

flatMap сглаживает наблюдаемое автоматически для нас, чтобы мы могли наблюдать поток json напрямую

наблюдаемый-это объект, который испускает поток событий: Next, Error и Completed.

когда ваша функция возвращает Observable, она возвращает не поток, а экземпляр Observable. Элемент flatMap оператор просто сопоставляет этот экземпляр потоку.

это поведение flatMap по сравнению с map: выполните данную функцию и сгладьте полученный объект в поток.

просто:

[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 преобразует элементы, излучаемые наблюдаемым в Наблюдаемые, затем сглаживают выбросы от них в один Наблюдаемый

клянусь, это определение все еще смущает меня, но я собираюсь объяснить его самым простым способом, который заключается в использовании примера

В Нашей Ситуации: у нас есть наблюдаемый, который возвращает данные (простой URL), которые мы собираемся использовать для выполнения HTTP-вызова, который вернет наблюдаемый, содержащий необходимые нам данные, чтобы вы могли визуализировать ситуацию следующим образом:

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));

С 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)})
})

здесь, чтобы показать эквивалентную реализацию 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

надеюсь, что это может помочь.

Оливье.