rxjs运算符`delay`的混乱行为

时间:2019-07-08 16:26:27

标签: rxjs reactivex rxjs-pipeable-operators

我对rxjs运算符delay有点困惑。

当我使用from创建的假可观察对象进行测试时,我只会看到 initial 延迟:

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

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

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

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

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

  

[...]此运算符将源可观察的时间偏移以毫秒为单位的时间量。值之间的相对时间间隔被保留。

但是,当我使用从事件创建的可观察对象进行测试时,我会在每个发射值之前看到延迟

const { fromEvent } = Rx;
const { delay } = RxOperators;

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

这是怎么回事?为什么delay在两种情况下的行为都不一样?

3 个答案:

答案 0 :(得分:2)

delay所做的一切就是说:每当接收到一个值时,它将在延迟期间保持该值,然后发出该值。它对收到的每个值执行相同的操作。 delay不会更改流中项目之间的相对时间。

因此,当您执行from([1,2,3,4]).pipe(delay(1000))时,会发生以下情况:

  • 时间0:from发出1
  • 时间0:delay看到1并启动timer1
  • 时间0:from发出2
  • 时间0:delay看到2并启动了timer2
  • ...
  • 时间1000:timer1完成并且delay发出1
  • 时间1000:timer2完成并且delay发出2
  • ...

因此,由于所有4个值都是快速连续发出的,因此您实际上只看到一个初始延迟,然后所有4个值都向下游发出。实际上,每个值都比最初发出时延迟了1秒。

如果您想“分散”这些物品,使它们至少相隔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));

这会将每个单独的值转换为可观察值,并在延迟后发出该值,然后将这些可观察值连接起来。这意味着每一项的计时器直到上一项的计时器完成后才会开始计时。

答案 1 :(得分:1)

在第一个代码段中,您逐个元素发射一个数组。首先延迟,然后处理数组元素。

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

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

“ fromEvent”和“ pipe”使每个事件“延迟”。每个事件之前的延迟的管道序列处理。

答案 2 :(得分:1)

点击流并获取发出的值,然后将它们传递到延迟中,延迟一秒钟后将其发出。管道中的每个函数都返回一个新的observable,它向管道中的下一个函数发出一个值。 Tap返回尚未延迟的相同可观察物,而延迟返回一秒钟后发出的可观察物。

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>