4

根据switchMap的定义

在每次发射时,先前的内部 observable(您提供的函数的结果)被取消并订阅新的 observable。您可以通过短语 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 秒

堆栈闪电链接

我发现很难理解这个概念,谢谢

4

2 回答 2

7

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

因此,如果您使用超时50001000则不能保证哪些操作会在 5 秒后首先发生。有时外部的 Observable 会先发射,有时内部的 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

于 2019-04-05T09:19:21.567 回答
3

我认为,您错误地假设您的源在25s第二个开始发射,而它开始于24s. 并且没有“默认0”。

Source 在 发射t0,然后在1sinnerinterval发射。在您从 source 切换到另一个值之前,Innerinterval将有 5 秒的时间发出 4timer5 次。如果您的源timer在 开始发出24s,那么您将在订阅中获得的第一个值是在25s-interval将发出其第一个值的时间。

45 次的原因是在 RxJS 和 JS 调度中。有关可能发生的事情的粗略示例,请参阅此stackblitz 。详细解释这一点需要更多的研究工作和时间

这是一个描绘mergeMap vs exhaustMap vs switchMap vs concatMap行为的大理石图,以便更好地理解:

合并映射 vs 排气映射 vs switchMap vs concatMap

检查这个mergeMap vs exhaustMap vs switchMap vs concatMap playground

于 2019-04-05T10:10:21.140 回答