Rxjs 不使用';不浪费工作

Rxjs 不使用';不浪费工作,rxjs,system.reactive,reactive-programming,Rxjs,System.reactive,Reactive Programming,我有一个可观测的可观测值,其中每个内部可观测值都会产生一个昂贵的计算值。我想要类似于Switch,但不会浪费工作的行为(SwitchFrugal?): 如果订阅了一个当前的内部可观察对象,我希望继续从它接收值,直到它完成为止 它不应该从开关中取消订阅 一旦当前内部可观察对象完成,应订阅最新的内部可观察对象(如果在当前之后有) 我一直在努力实现这种行为。使用现有的操作符是否可行?或者,是否需要通过可观察。创建“从头开始”执行此操作 我会这样做: const subject = new Su

我有一个可观测的可观测值,其中每个内部可观测值都会产生一个昂贵的计算值。我想要类似于
Switch
,但不会浪费工作的行为(
SwitchFrugal
?):

  • 如果订阅了一个当前的内部可观察对象,我希望继续从它接收值,直到它完成为止
    • 它不应该从
      开关中取消订阅
  • 一旦当前内部可观察对象完成,应订阅最新的内部可观察对象(如果在当前之后有)
我一直在努力实现这种行为。使用现有的操作符是否可行?或者,是否需要通过
可观察。创建
“从头开始”执行此操作

我会这样做:

const subject = new Subject();
const start = Scheduler.async.now();

// Simulated source Observable
const source = Observable
    .timer(0, 900)
    .map(i => Observable.defer(() => {
        console.log('Subscribe inner Observable:', i);
        return Observable
            .timer(0, 400)
            .take(6)
            .map(j => i.toString() + ':' + j.toString());
    }))
    .share();

source
    .merge(subject
        .withLatestFrom(source)
        .map(([v, observable]) => {
            return observable;
        })
    )
    .exhaustMap(obs => obs.finally(() => subject.next()))
    .subscribe(val => console.log(Scheduler.async.now() - start, val));
我在模拟一个发射可见光的源可见光。外部可观测的发射速度比内部可观测的发射速度快,因此这应该可以模拟您的情况

然后我将
源代码
合并到链中,但仅当
主题
发出时。然后在
finally
操作符中触发主题

结果如下:

Subscribe inner Observable: 0
45 '0:0'
452 '0:1'
856 '0:2'
1260 '0:3'
1665 '0:4'
2065 '0:5'
Subscribe inner Observable: 2
2069 '2:0'
2472 '2:1'
2876 '2:2'
3280 '2:3'
3683 '2:4'
4084 '2:5'
Subscribe inner Observable: 4
4086 '4:0'
4487 '4:1'
请注意,当第一个内部可见光完成时,源的最新发射是一个具有
i==2
的可见光。如果您运行此代码,您将看到这三种排放之间没有时间间隔(jsbin现在已被破坏,因此我无法登录并进行演示):

如果您将其与未使用
merge()
的默认行为进行比较,您将看到
exhaustMap
需要等待,直到有另一个排放源:

source
    .exhaustMap(obs => obs.finally(() => subject.next()))
    .subscribe(console.log);
这将打印以下内容。请注意时间间隔,它使用
i==3
而不是
2
订阅内部可观察项:

Subscribe inner Observable: 0
45 '0:0'
449 '0:1'
853 '0:2'
1257 '0:3'
1659 '0:4'
2064 '0:5'
Subscribe inner Observable: 3
2748 '3:0'
3151 '3:1'
3553 '3:2'
3953 '3:3'
4355 '3:4'
4759 '3:5'
Subscribe inner Observable: 6
5458 '6:0'
5863 '6:1'
Subscribe inner Observable: 0
2803 '0:0'
3208 '0:1'
3615 '0:2'
4016 '0:3'
Subscribe inner Observable: 1
4853 '1:0'
5254 '1:1'
5658 '1:2'
6061 '1:3'
Subscribe inner Observable: 2
7814 '2:0'
8218 '2:1'
8622 '2:2'
9026 '2:3'
Subscribe inner Observable: 3
9180 '3:0'
9583 '3:1'
9987 '3:2'
10391 '3:3'
Subscribe inner Observable: 5
10393 '5:0'
10796 '5:1'
编辑:

为了避免两次订阅相同的内部可观测数据(假设这些是冷可观测数据),我可以跟踪我已经订阅的可观测指数以及接下来需要的指数:

我将使源以随机间隔发射,并减少值:

const source = Observable.range(0, 100, Scheduler.async)
    .concatMap(i => Observable.of(i).delay(Math.random() * 3000))
    .map(i => Observable.defer(() => {
        console.log('Subscribe inner Observable:', i);
        return Observable
            .timer(0, 400)
            .take(4)
            .map(j => i.toString() + ':' + j.toString());
    }))
    .map((observable, index) => [observable, index])
    .share();
然后发送我们使用
subject.next()
处理的索引,并忽略我们不想要的观察值:

source
    .merge(subject
        .withLatestFrom(source)
        .map(([processedIndex, observableAndIndex]) => {
            let observableIndex = observableAndIndex[1];
            if (processedIndex < observableIndex) {
                return observableAndIndex;
            }
            return false;
        })
        .filter(Boolean)
    )
    .exhaustMap(([observable, index]) => observable.finally(() => subject.next(index)))
    .subscribe(val => console.log(Scheduler.async.now() - start, val));

是不是或者你在寻找什么?@martin
排气
/
排气地图
开关优先
相同,这几乎是我想要的,只是它不满足第二个要点:“一旦当前内部可观察对象完成,应该订阅最新的内部可观察对象(如果在当前之后有)你能为你要找的东西添加一个大理石图吗?@DanielT。我添加了一个大理石图。@Timothyshiels-这不正是
Merge
所做的吗?这看起来非常接近,谢谢!我认为唯一的问题是,如果一个内部可观察对象完成,并且没有新的内部可观察对象到达,那么相同的可观察对象将再次订阅。如果源可观测发射出一个单一的可观测,然后再也没有完成,这难道不会一次又一次地订阅同一个内部可观测吗?(我要到星期一才能尝试。)@TimothyShields这对冷观测是正确的(如果你在热观测完成后订阅了它,它不会做任何事情)。看到我的更新,你可以简单地跟踪你已经订阅的索引,最终忽略你不想要的观察值。
Subscribe inner Observable: 0
2803 '0:0'
3208 '0:1'
3615 '0:2'
4016 '0:3'
Subscribe inner Observable: 1
4853 '1:0'
5254 '1:1'
5658 '1:2'
6061 '1:3'
Subscribe inner Observable: 2
7814 '2:0'
8218 '2:1'
8622 '2:2'
9026 '2:3'
Subscribe inner Observable: 3
9180 '3:0'
9583 '3:1'
9987 '3:2'
10391 '3:3'
Subscribe inner Observable: 5
10393 '5:0'
10796 '5:1'