Javascript 为什么我们需要使用 flatMap?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33471526/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 15:06:56  来源:igfitidea点击:

Why do we need to use flatMap?

javascriptrxjs

提问by user233232

I am starting to use RxJS and I don't understand why in this example we need to use a function like flatMapor concatAll; where is the array of arrays here?

我开始使用 RxJS,但我不明白为什么在这个例子中我们需要使用像flatMapor 之类的函数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)})

If someone can visually explain what is happening, it will be very helpful.

如果有人可以直观地解释正在发生的事情,那将非常有帮助。

采纳答案by user3743222

When I started to have a look at RxjsI also stumbled on that stone. What helped me is the following:

当我开始看时,Rxjs我也偶然发现了那块石头。对我有帮助的是以下内容:

  • documentation from reactivex.io . For instance, for flatMap: http://reactivex.io/documentation/operators/flatmap.html
  • documentation from rxmarbles : http://rxmarbles.com/. You will not find flatMapthere, you must look at mergeMapinstead (another name).
  • the introduction to Rx that you have been missing: https://gist.github.com/staltz/868e7e9bc2a7b8c1f754. It addresses a very similar example. In particular it addresses the fact that a promise is akin to an observable emitting only one value.
  • finally looking at the type information from RxJava. Javascript not being typed does not help here. Basically if Observable<T>denotes an observable object which pushes values of type T, then flatMaptakes a function of type T' -> Observable<T>as its argument, and returns Observable<T>. maptakes a function of type T' -> Tand returns Observable<T>.

    Going back to your example, you have a function which produces promises from an url string. So T' : string, and T : promise. And from what we said before promise : Observable<T''>, so T : Observable<T''>, with T'' : html. If you put that promise producing function in map, you get Observable<Observable<T''>>when what you want is Observable<T''>: you want the observable to emit the htmlvalues. flatMapis called like that because it flattens (removes an observable layer) the result from map. Depending on your background, this might be chinese to you, but everything became crystal clear to me with typing info and the drawing from here: http://reactivex.io/documentation/operators/flatmap.html.

  • 来自reactivex.io 的文档。例如,对于flatMaphttp: //reactivex.io/documentation/operators/flatmap.html
  • 来自 rxmarbles 的文档:http://rxmarbles.com/ 。你不会在flatMap那里找到,你必须去看看mergeMap(另一个名字)。
  • 您错过的 Rx 介绍:https: //gist.github.com/staltz/868e7e9bc2a7b8c1f754。它解决了一个非常相似的例子。特别是它解决了一个事实,即承诺类似于仅发出一个值的可观察对象。
  • 最后看看来自 RxJava 的类型信息。未输入 Javascript 在这里没有帮助。基本上 ifObservable<T>表示一个可观察的对象,它推送类型 T 的值,然后flatMap将类型的函数T' -> Observable<T>作为其参数,并返回Observable<T>map接受一个类型的函数T' -> T并返回Observable<T>.

    回到您的示例,您有一个从 url 字符串生成 promise 的函数。所以T' : string, 和T : promise。而从我们之前所说的promise : Observable<T''>,所以T : Observable<T''>,与T'' : html. 如果你把那个 Promise 生成函数放在 中map,你就会得到Observable<Observable<T''>>你想要的Observable<T''>:你想要 observable 发出html值。flatMap之所以这样称呼是因为它使map. 根据您的背景,这对您来说可能是中文,但是通过输入信息和从这里绘制的图,一切都变得清晰起来:http: //reactivex.io/documentation/operators/flatmap.html

回答by serkan

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

You use flatMap when you have an Observable whose results are more Observables.

当你有一个 Observable 的结果是更多的 Observable 时,你可以使用 flatMap。

If you have an observable which is produced by an another observable you can not filter, reduce, or map it directly because you have an Observable not the data. If you produce an observable choose flatMap over map; then you are okay.

如果你有一个由另一个 observable 产生的 observable,你不能直接过滤、减少或映射它,因为你有一个 Observable 而不是数据。如果你产生一个 observable 选择 flatMap 而不是 map;那么你没事。

As in second snippet, if you are doing async operation you need to use 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>

回答by Emmanuel Osimosu

flatMaptransform the items emitted by an Observable into new Observables, then flattens the emissions from those into a single Observable.

flatMap将 Observable 发出的项目转换为新的 Observable,然后将这些项目的排放扁平化为单个 Observable。

Check out the scenario below where get("posts")returns an Observable that is "flattened" by flatMap.

查看下面的场景,其中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.

回答by Hamed Baatour

People tend to over complicate thingsby giving the definition which says:

人们倾向于通过给出以下定义来使事情变得过于复杂

flatMap transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable

flatMap 将 Observable 发出的项目转换为 Observable,然后将这些项目的发射展平为单个 Observable

I swear this definition still confuses me but I am going to explain it in the simplest way which is by using an example

我发誓这个定义仍然让我感到困惑,但我将以最简单的方式解释它,那就是使用一个例子

Our Situation: we have an observable which returns data(simple URL) that we are going to use to make an HTTP call that will return an observable containing the data we need so you can visualize the situation like this:

我们的情况:我们有一个 observable,它返回数据(简单 URL),我们将使用它来进行 HTTP 调用,该调用将返回一个包含我们需要的数据的 observable,以便您可以像这样可视化情况:

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

so as you can see we can't reach the data we need directly so the first way to retrieve the data we can use just normal subscriptions like this:

如您所见,我们无法直接获取所需的数据,因此第一种检索数据的方法可以使用普通订阅,如下所示:

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

this works but as you can see we have to nest subscriptions to get our data this currently does not look bad but imagine we have 10 nested subscriptions that would become unmaintainable.

这是有效的,但正如您所看到的,我们必须嵌套订阅才能获取我们的数据,这目前看起来还不错,但想象一下,我们有 10 个无法维护的嵌套订阅。

so a better way to handle this is just to use the operator flatMapwhich will do the same thing but makes us avoid that nested subscription:

所以处理这个问题的更好方法是使用操作符flatMap,它会做同样的事情,但让我们避免嵌套订阅:

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

回答by drpicox

Simple:

简单的:

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

回答by Lucius

It's not an array of arrays. It's an observable of observable(s).

它不是数组数组。它是一个 observable 的 observable(s)。

The following returns an observable stream of string.

下面返回一个可观察的字符串流。

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

While this returns an observable stream of observable stream of json

虽然这会返回 json 的可观察流的可观察流

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

flatMapflattens the observable automatically for us so we can observe the json stream directly

flatMap为我们自动展平 observable 以便我们可以直接观察 json 流

回答by AkkarinZA

An Observable is an object that emits a stream of events: Next, Error and Completed.

Observable 是一个发出事件流的对象:Next、Error 和 Completed。

When your function returns an Observable, it is not returning a stream, but an instance of Observable. The flatMapoperator simply maps that instance to a stream.

当你的函数返回一个 Observable 时,它​​不是返回一个流,而是一个 Observable 的实例。该flatMap运算符只是将该实例映射到流。

That is the behaviour of flatMapwhen compared to map: Execute the given function and flatten the resulting object into a stream.

这是与以下行为flatMap相比的行为map:执行给定的函数并将结果对象展平为流。

回答by olivier cherrier

Here to show equivalent implementation of a flatMap using subscribes.

这里展示了使用订阅的 flatMap 的等效实现。

Without flatMap:

没有平面地图:

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

With 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

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

Hope it could help.

希望它能有所帮助。

Olivier.

奥利维尔。

回答by Thanawat

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

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