2015-11-02 2 views
44

Я начинаю использовать RxJS, и я не понимаю, почему в этом примере нам нужно использовать такую ​​функцию, как flatMap или concatAll; где массив массивов здесь?Зачем нам нужно использовать 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(url => {console.log(url)}) 

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

+1

этот ответ велик из-за ценных ссылок, которые он предоставляет, но терминология rxjs не хорошо переводится на английский. (фотографии лучше). Вот почему я рекомендую вместо этого использовать простые примеры, подобные этому, или более сложные примеры в репозитории rxjs и добавление операторов «.do» до и после оператора flatmap и map, а затем просто установление точки останова с помощью отладчика Chrome. вы сразу увидите, что каждый из них производит другой вывод. – HipsterZipster

+1

Я думаю, что если 'flatMap' был бы назван' mapThenFlatten', тогда он был бы менее запутанным. – goat

ответ

46

Когда я начал иметь посмотрите на Rxjs Я также наткнулся на этот камень. Что мне помогло:

  • документация от reactivex.io. Например, для flatMap: http://reactivex.io/documentation/operators/flatmap.html
  • документация от rxmarbles: http://rxmarbles.com/. Вы не найдете flatMap там, вы должны посмотреть на switchMap вместо этого (другое имя).
  • введение в 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.

+1

Я забыл упомянуть, что вы должны иметь возможность упростить 'return Rx.Observable.fromPromise (jQuery.getJSON (requestUrl)); 'to' return jQuery.getJSON (requestUrl); 'как' flatMap' также принимает функцию выбора, которая возвращает обещание, т. е. функцию типа 'T '-> Promise'. – user3743222

+0

Ничего себе, что GitHub Gist (https: //gist.github.com/staltz/868e7e9bc2a7b8c1f754) является чертовски фантастическим. Я рекомендую его всем, кто работает с любыми библиотеками ReactiveX, такими как RxJS. –

13

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

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

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

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

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

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

+2

Трудно понять эту концепцию, можете ли вы добавить комментарии к визуальному, что вы подразумеваете «возвращает наблюдаемый поток наблюдаемого потока json». Благодарю. – user233232

+0

@ user233232, как [x, x, x, x] до [[xxx], [[xxx], [xxx]]] – serkan

7

Наблюдаемый объект, который излучает поток событий: Далее, Ошибка и завершено.

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

Это поведение flatMap по сравнению с map: Выполнение данной функции и сглаживание результирующего объекта в поток.

+1

это очень хороший ответ –

67
['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, если у вас есть наблюдаемый, результаты которого больше Observables.

Если у вас есть наблюдаемое, которое создается другим наблюдаемым, вы не можете фильтровать, уменьшать или отображать его напрямую, потому что у вас есть Наблюдаемый, а не данные. Если вы создаете наблюдаемый, выберите flatMap over map; то с тобой все в порядке.

Как и во втором фрагменте, если вы выполняете операцию async, вам нужно использовать 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>

2

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

Простые:

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

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. 
+1

Ницца, простой ответ. Я думаю, что это может быть лучше. – vaughan

3

Людей, как правило, более усложнять, давая определение, которое говорит:

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

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

Надеется, что это может помочь.

Olivier.

Смежные вопросы