rxjs operator `delay` 的混淆行为

Confusing behavior of rxjs operator `delay`

我对 rxjs 运算符有点困惑 delay

当我用 from 创建的假 observable 测试它时,我只看到 initial 延迟:

const { from } = Rx;
const { delay, tap } = RxOperators;

from([1, 2, 3, 4]).pipe(
  tap(console.log),
  delay(1000));

(您可以将此代码片段复制并粘贴到 rxviz。)

我在其中放置了一个 tap 以确保 from 实际上将数组项作为单独的值而不是单个数组值发出。

最初的延迟不是我所期望的,但至少 the docs 是这么说的:

[...] this operator time shifts the source Observable by that amount of time expressed in milliseconds. The relative time intervals between the values are preserved.

但是,当我使用从事件创建的可观察对象对其进行测试时,我看到在每个发出的值:

之前有一个延迟
const { fromEvent } = Rx;
const { delay } = RxOperators;

fromEvent(document, 'click')
  .pipe(delay(1000))

这是怎么回事?为什么 delay 在这两种情况下表现不同?

在第一个代码片段中,您逐个元素地发出一个数组。先延迟,再处理数组元素。

'from' 和 'pipe' 使 'delay' 执行一次。管道序列处理,先延迟,然后点击,点击,点击,点击。

在第二个代码片段中,您正在发射对象(它们到达),因此每个对象都会发生一次延迟。

'fromEvent' 和 'pipe' 使每个事件成为 'delay'。管道顺序处理每个事件之前的延迟。

您点击流并获取发出的值,然后将它们通过管道传输到延迟中,延迟会在一秒钟后发出它们。管道中的每个函数 returns 一个新的可观察对象,它向管道中的下一个函数发出一个值。点击 returns 尚未延迟的同一个 Observable 并延迟 returns 一个稍后发出的 Observable。

const { from } = rxjs;
const { delay, tap } = rxjs.operators;

from([1, 2, 3, 4]).pipe(
  tap(val => { console.log(`Tap: ${val}`); }),
  delay(1000)).subscribe(val => { console.log(`Sub: ${val}`); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.2/rxjs.umd.min.js"></script>

如果你在延迟后点击,那么你会在延迟后看到它们。

const { from } = rxjs;
const { delay, tap } = rxjs.operators;

from([1, 2, 3, 4]).pipe(
  delay(1000),
  tap(val => { console.log(`Tap: ${val}`); })).subscribe(val => { console.log(`Sub: ${val}`); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.2/rxjs.umd.min.js"></script>

所有 delay 所做的就是它所说的:每当它收到一个值时,它都会在延迟期间保留该值,然后发出它。它对接收到的每个值都做同样的事情。 delay 不会 改变流中项目之间的相对时间。

所以,当您执行 from([1,2,3,4]).pipe(delay(1000)) 时,会发生什么:

  • 时间 0:from 发出 1
  • 时间 0:delay 看到 1 并启动定时器 1
  • 时间 0:from 发出 2
  • 时间 0:delay 看到 2 并启动定时器 2
  • ...
  • 时间 1000:计时器 1 完成并且 delay 发出 1
  • 时间 1000:计时器 2 完成并且 delay 发出 2
  • ...

因此,因为所有 4 个值都是快速连续发出的,所以您实际上只看到初​​始延迟,然后所有 4 个值都在下游发出。实际上,每个值都从最初发出时延迟了 1 秒。

如果您想要 "spread apart" 项目以使它们至少相隔 1 秒,那么您可以这样做:

const source = from([1, 2, 3, 4])
const spread = source.pipe(concatMap(value => of(value).pipe(delay(1000))));
spread.subscribe(value => console.log(value));

这会将每个单独的值转换为可观察值,在延迟后发出值,然后连接这些可观察值。这意味着每个项目的计时器在前一个项目的计时器结束之前不会开始计时。