请按照示例说明RxJS映射和switchMap之间的区别

时间:2019-10-19 17:23:21

标签: rxjs

我已经看过许多其他有关该主题的文章,并且阅读了https://www.learnrxjs.io/operators/transformation/switchmap.html之类的官方(见下文)和半官方文档,但是我仍然无法内化“地图”和“ switchMap”,并希望通过下面的具体示例进行说明。

根据RxJS官方文档的说明:

出于对我的不全面理解,我做了一些非常简单的示例,请参见StackBlitz https://stackblitz.com/edit/rxjs-xpicph?devtoolsheight=60,但仍然不完全理解为什么某些示例以它们的方式产生其输出的原因。

首先,提供一些非常简单的string示例:

// String Example 1

const source = of('World').pipe(
  map(x => `Hello ${x}!`)
);

source.subscribe(x => console.log(`SOURCE (map): ${x}`));

// SOURCE (map): Hello World!

好的,很公平,我想我主要是得到这个。

  1. “ Of”向“管道”发出“世界”作为值(或者在这个阶段排放仍然是可观察的?)
  2. “管道”提供“世界”作为“地图”的值(或者它仍然是可观察的?)
  3. “地图”将此(值?可观察?)投影到“ Hello World”,等待所有字符完成,然后将此(值?可观察?)返回到“管道”
  4. “管道”然后返回一个Observable。

因此,我们得到输出:“ Hello World”

// String Example 2

const otherSource = of('World').pipe(
  switchMap(x => `Hello ${x}!`)
);

otherSource.subscribe(x => console.log(`SOURCE (switchMap): ${x}`));

// SOURCE (switchMap): H
// SOURCE (switchMap): e
// SOURCE (switchMap): l
// SOURCE (switchMap): l
// SOURCE (switchMap): o
// SOURCE (switchMap):
// SOURCE (switchMap): W
// SOURCE (switchMap): o
// SOURCE (switchMap): r
// SOURCE (switchMap): l
// SOURCE (switchMap): d
// SOURCE (switchMap): !

哇!劳驾?刚刚发生了什么?

  1. “ Of”向“管道”发出“世界”作为价值(或者在这个阶段排放仍然是可观察的?)
  2. “管道”向“ switchMap”提供“世界”作为值(还是仍然可观察?),
  3. “ switchMap”将此(值?Observable?)投影到“ Hello World”,但是与“ map”不同,它不等待所有字符完成才输出一系列“ Observables”(或值?)。 ,并且每个字符可观察一个吗?还是每个字符发射一次的Observable?
  4. “管道”然后在每个字符上返回一个Observable?

问题:这里的引擎盖下面到底是怎么回事?

让我们继续看另一组简单的示例,然后希望将所有内容捆绑在一起:

// OBJECT EXAMPLES

const foo = {
  "first": 1,
  "second": 2
}

// OBJECT EXAMPLE 1

Object.keys(foo).forEach(obj=>of(foo[obj]).pipe(
  map(x=>x*2)
).subscribe(x => console.log(`SOURCE (map): ${x}`)))

// SOURCE (map): 2
// SOURCE (map): 4

好的,很公平。这似乎很简单

// OBJECT EXAMPLE 2

Object.keys(foo).forEach(obj=>of(foo[obj]).pipe(
  switchMap(x=>of(x*2))  // WHY DO WE NEED ANOTHER "of()" HERE? "switchMap(x=>x*2)" DOESN'T COMPILE
).subscribe(x=> console.log(`SOURCE (switchMap): ${x}`)))

// SOURCE (switchMap): 2
// SOURCE (switchMap): 4

非常清楚,但是为什么我们需要向“ switchMap”提供“ of(x * 2)?”在STRING示例2中,“ switchMap”看起来像疯了似的,并自动将其输出包装为Observable(或者“ pipe” “将输出包装为Observable?),但是无论如何,“ switchMap”和“ pipe”不需要任何额外的“ of()”或任何其他将输出包装为Observable的帮助,但是在对象示例2中,我们明确需要提供第二个“ of()”以确保“ switchMap”的输出是可观察到的,否则代码不会编译。(但是对于“ map”,我们不需要提供第二个“ of()“)。再一次,为什么要区别呢?

因此,总而言之,如果有人可以解释,我将非常感激:

  1. 在上面的示例中,链中的哪个点正在处理值(即,来自可观测值的排放),以及在哪个点处涉及可观测值?
  2. 为什么“ switchMap”提供了表2所示的明显的解析行为?
  3. 为什么在对象示例2中需要为“ switchMap”提供“ of()”,而在STRING示例2中则不需要? (并且,类似地,为什么“ map”不需要第二个“ of()”?)

提前谢谢!

1 个答案:

答案 0 :(得分:1)

  1. 对于您的示例运算符,这些是类型转换:

    • of:接收类型为T的参数,生成单个类型为T的通知,然后完成
    • map:接收类型为T => R的参数,每当接收到类型为R的通知时,都会生成类型为T的通知
    • switchMap收到类型为T => ObservableLike<R>的参数,每当收到类型为R的通知时,都会产生类型为T的通知

  1. 我认为这是主要的困惑。 switchMap具有投影函数,期望将ObservableLike<R>作为返回类型。该语句的重要部分是Observable Like (可观察到的)。

有时是违反直觉的,但是RxJS会在内部尽可能地在Observables中转换其他类型,例如:

  • 数组或
  • 承诺

在可以提供ObservableLike的地方使用数组时,RxJS将数组视为值流。

例如,说我将这个数组转换为可观察的:

from([1, 2, 3])

我订阅的内容是:

// 1
// 2
// 3

由于string只不过是Array<char>,因此RxJS会尝试将此字符串转换为它的字符流。 (char实际上不是JS中的数据类型,但内部字符串是数组)

即这些是相等的:

  • from(['a', 'b', 'c'])
  • from('abc')

  1. 我认为以上答案可以解释这一点。您总是需要为ObservableLike提供一个switchMap,但是string类型恰好是ObservableLike-只是一个字符流。 / li>