为什么我们需要使用 flatMap?

IT技术 javascript rxjs
2021-01-29 08:59:14

我开始使用 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)})

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

6个回答
['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 而不是数据。如果你产生一个 observable 选择 flatMap 而不是 map;那么你没事。

与第二个片段一样,如果您正在进行异步操作,则需要使用 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>

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

  • 来自reactivex.io 的文档。例如,对于flatMaphttp : //reactivex.io/documentation/operators/flatmap.html
  • 来自 rxmarbles 的文档:http: //rxmarbles.com/ 你不会在flatMap那里找到,你必须去看看mergeMap(另一个名字)。
  • 您错过的 Rx 介绍:https : //gist.github.com/staltz/868e7e9bc2a7b8c1f754它解决了一个非常相似的例子。特别是它解决了这样一个事实,即Promise类似于仅发出一个值的 observable。
  • 最后看看来自 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

我忘了提到你应该能够简化return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));return jQuery.getJSON(requestUrl);asflatMap也接受一个选择器函数,它返回一个 promise ie 类型的函数T' -> Promise
2021-03-17 08:59:14
@JacobStamm 我同意。只是让事情变得更容易。
2021-03-19 08:59:14
哇,GitHub Gist ( gist.github.com/staltz/868e7e9bc2a7b8c1f754 ) 太棒了。我向任何使用 ReactiveX 库(如 RxJS)的人推荐它。
2021-03-26 08:59:14
您可以用 X 或 Y 替换 T' 而不改变答案中任何地方的含义。箭头是类型签名的 Haskell 符号。所以 T' -> T 是一个函数的签名,它接受一个类型为 T' 的元素并返回一个类型为 T 的元素
2021-03-31 08:59:14
这个语法是什么意思:T’ -> T我理解T为泛型,但撇号和非粗箭头是什么?
2021-04-05 08:59:14

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

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

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


我们的简单例子

1- 我们有一个 observable,它返回一个简单的 URL 字符串。

2- 我们必须使用该 URL 进行第二次 HTTP 调用。

3- 第二个 HTTP 调用将返回一个包含我们需要的数据的 observable。


所以我们可以想象这样的情况:

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 将 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.
“flatMap 将 Observable 发出的项目转换为新的 Observable,然后将这些项目的排放扁平化为单个 Observable。” 这是极好的东西。
2021-03-21 08:59:14
很好,简单的答案。我认为这可能是最好的。
2021-04-12 08:59:14

简单的:

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