了解 rxjs 中的 SwitchMap

Understanding SwitchMap in rxjs

根据 switchMap 的定义

On each emission the previous inner observable (the result of the function you supplied) is cancelled and the new observable is subscribed. You can remember this by the phrase switch to a new observable.

现在,我有这样的代码

const source = timer(0, 5000).pipe(map(x=>`${x}`));
const example = source.pipe(switchMap((f) => interval(1000).pipe(map(y=>`f${f}-s${y}`))),take(20));
const subscribe = example.subscribe(val => console.log(val+' '+ new Date().getSeconds()));

结果是这样

我的问题是,

  1. 第25秒-外层函数被调用,内层函数尚未触发,所以外层函数的最新值为0,内层函数也默认为0,因为它有还没有值 f0-s0 25

  2. 第 26 秒 - 内部函数被调用,理想情况下该值应为 0,因为该函数只是第一次被调用,但它是 1,即。 f0-s1 26

  3. 第 30 秒 - 调用外部函数将内部函数值重置为 0,即。 f1-s0 30

  4. 为什么第35秒内函数重置了,还剩1秒

stackblitz link

我觉得这个概念很难理解,谢谢

这是因为默认情况下,RxJS 的异步操作使用 setTimeoutsetInterval 函数,这些函数不能保证它们会准确地达到您想要的超时。

因此,如果您使用超时 50001000,则无法保证 5 秒后哪个操作会先发生。有时外层 Observable 先发出,有时内层先发出,但 switchMap 对此无能为力。

你可以看到时间有多么不同,例如。这个:

const start = new Date().getTime();
setInterval(() => console.log(new Date().getTime() - start), 1000);

现场演示:https://stackblitz.com/edit/typescript-urep5j

1004
2001
3002
4000
4998
...

所以有时延迟是 1004 而其他时候只是 998.

我认为,您错误地假设源在 25s 秒开始发射,而它在 24s 开始。而且没有 "default 0".

源在 t0 发射,然后在 1s 内部 interval 发射。内部 interval 将有 5 秒的时间发出 4 5 次,然后您将从源 timer 切换到另一个值。如果您的源 timer24s 开始发射,那么您将在订阅中获得的第一个值是在 25s — 当 interval 将发射它的第一个值时。

4次5次的原因在于RxJS和JS调度。请参阅此 stackblitz for a rough example,了解可能发生的情况。详细解释这一点需要 更多的研究工作和时间

这里是描述 mergeMap vs exhaustMap vs switchMap vs concatMap 行为的弹珠图,以便更好地理解:

检查此 mergeMap vs exhaustMap vs switchMap vs concatMap playground