Javascript 按RxJS中的特定时间量分离可观测值

Javascript 按RxJS中的特定时间量分离可观测值,javascript,system.reactive,rxjs,Javascript,System.reactive,Rxjs,哪种最惯用的方法可以产生特定时间内可观察到的值?例如,假设我从一个大数组中创建了一个可观测值,我希望每2秒生成一个值。interval和selectMany的组合是最好的方法吗?对于您的具体示例,我们的想法是将数组中的每个值映射到一个可观察值,该值将在延迟后产生其结果,然后连接产生的可观察值流: var delayedStream = Rx.Observable .fromArray([1, 2, 3, 4, 5]) .map(function (value) { return

哪种最惯用的方法可以产生特定时间内可观察到的值?例如,假设我从一个大数组中创建了一个可观测值,我希望每2秒生成一个值。
interval
selectMany
的组合是最好的方法吗?

对于您的具体示例,我们的想法是将数组中的每个值映射到一个可观察值,该值将在延迟后产生其结果,然后连接产生的可观察值流:

var delayedStream = Rx.Observable
    .fromArray([1, 2, 3, 4, 5])
    .map(function (value) { return Rx.Observable.return(value).delay(2000); })
    .concatAll();
其他示例可能确实使用了
计时器
间隔
。这要看情况而定

例如,如果您的数组非常大,那么上述操作将导致相当大的内存压力(因为它正在为非常大的
N
数组创建
N
可观察值)。下面是一个使用
interval
惰性地遍历阵列的替代方法:

var delayedStream = Rx.Observable
    .interval(2000)
    .take(reallyBigArray.length) // end the observable after it pulses N times
    .map(function (i) { return reallyBigArray[i]; });

这一个将每隔2秒从数组中产生下一个值,直到它遍历整个数组。

布兰登的回答得到了想法的要点,这里有一个版本,它立即产生第一个项目,然后在以下项目之间留出时间

var delay = Rx.Observable.empty().delay(2000);

var items = Rx.Observable.fromArray([1,2,3,4,5])
  .map(function (x) {
    return Rx.Observable.return(x).concat(delay); // put some time after the item
  })
  .concatAll();
更新的RxJS版本:

var delay = Rx.Observable.empty().delay(2000);

var items = Rx.Observable.fromArray([1,2,3,4,5])
  .concatMap(function (x) {
    return Rx.Observable.of(x).concat(delay); // put some time after the item
  });

我认为使用zip可以生成更好、更可读的代码,仍然只使用3个可观察对象

var items = ['A', 'B', 'C'];

Rx.Observable.zip(
  Rx.Observable.fromArray(items),
  Rx.Observable.timer(2000, 2000),  
  function(item, i) { return item;}
)

同意zip是一种干净的方法。下面是一个可重用函数,用于为阵列生成间隔流:

function yieldByInterval(items, time) {
  return Rx.Observable.from(items).zip(
    Rx.Observable.interval(time),
    function(item, index) { return item; }
  );
}

// test
yieldByInterval(['A', 'B', 'C'], 2000)
  .subscribe(console.log.bind(console));
这是基于的,但是使用
.zip
作为实例方法会稍微短一些

另外,我使用了
Rx.Observable.from()
,因为
Rx.Observable.fromArray()
对于RxJS 5来说是。

Rx.Observable.from([1, 2, 3, 4, 5])
  .zip(Rx.Observable.timer(0, 2000), x => x)
  .subscribe(x => console.log(x));

由于没有提到这一点,我认为与的结合是相当可读的

Rx.Observable.fromArray([1, 2, 3, 4, 5])
    .concatMap(x => Rx.Observable.of(x).delay(1000));

请参见

,了解RxJS v6如何以2秒的延迟获得下一个版本

示例1.concatMap:

import {of} from 'rxjs';
import {concatMap, delay} from 'rxjs/operators';

of(1, 2, 3, 4, 5)
  .pipe(
    concatMap(x => of(x)
      .pipe(
        delay(2000))
    )
  )
  .subscribe({
    next(value) {
      console.log(value);
    }
  });
示例2.地图+目录:

import {of} from 'rxjs';
import {concatAll, delay, map} from 'rxjs/operators';

of(1, 2, 3, 4, 5)
  .pipe(
    map(x => of(x)
      .pipe(
        delay(2000))
    ),
    concatAll()
  )
  .subscribe({
    next(value) {
      console.log(value);
    }
  });

以farincz和user3587412的zip解决方案为基础,以下是它在RxJSV6中的工作原理

const { zip, from, timer } = require("rxjs")
const { map } = require("rxjs/operators")

const input = [1, 2, 3, 4, 5]
const delay = 2000

zip(
    from(input),
    timer(0, delay)
).pipe(
    map(([ delayedInput, _timer ]) => delayedInput) // throw away timer index
).subscribe(
    console.log
)

RxJs 6立即发出第一项并延迟剩余项的代码:

import { of, EMPTY, concat } from "rxjs";
import { concatMap, delay } from "rxjs/operators";

const delayed$ = EMPTY.pipe(delay(1000));

console.log("start");
of(1, 2, 3, 4)
  .pipe(concatMap(v => concat(of(v), delayed$)))
  .subscribe({
    next: console.log
  });

想法:

  • 对于每个项目,我们创建一个可观察的(使用
    concat
    ),它将立即输出项目(
    of(v)
    ),然后在延迟后发出一个
    空的
    可观察的
  • 由于我们使用的是
    concatMap
    ,所有发射的可见光都将以正确的顺序发射

注意
返回
现在是的
:现在可以是
concatMap
(猜测concatMap比2014年更新?)。这只是将它们全部排在一起(否则它们都会随着延迟一起发出),例如
.concatMap(x=>Observable.of(x).concat(Observable.empty().delay(5000))
Simon,可以用新的命名约定和简化更新答案。Thx。这对我来说是最好的解决办法。我想立即显示通知(如toast通知),但如果两个通知同时到达,则延迟第二个通知:-)可能应该在计时器中添加
take(items.length)
操作符,以允许obervable完成
take(items.length)
完全没有用。流本身是不可变的对象,take(或任何其他操作)不会影响可观察的源,而是从中派生一个新对象。这意味着你的提案只创建了4个observables,而不是3个。
zip
的完成由源数组管理,所有内存清理都由rxjscarear完成-我认为这在大多数实际情况下可能不起作用/第一个可观察(项)在不可预测的时间推送项。设想eg项目延迟10秒。当它产生它的项目时,计时器已经勾选了5次,所以所有的项目将立即被推出,而不是间隔2秒each@Bogey你是对的,这只是单独的阵列或“快速”观测值
import { of, EMPTY, concat } from "rxjs";
import { concatMap, delay } from "rxjs/operators";

const delayed$ = EMPTY.pipe(delay(1000));

console.log("start");
of(1, 2, 3, 4)
  .pipe(concatMap(v => concat(of(v), delayed$)))
  .subscribe({
    next: console.log
  });