我有一个用例,当需要另一个通知程序Observable发出时,我需要一个Observable跳过它的下一个发射。
source: |---X---X---X---X---X---X---X---X---X---X--|>
notifier: |-------------X---------X----------X-------|>
result: |---X---X---X-------X---X-------X-------X--|>
基本上,我想要一个名为skipNextWhen
的运算符,它接收通知符observable并跳过源的下一个发射。
我尝试使用使用pausable
运算符的实现(使用switchMap
重新实现),但无法使其工作。
pausable.ts
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/observable/never';
import 'rxjs/add/operator/startWith';
declare module 'rxjs/Observable' {
interface Observable<T> {
pausable: typeof pausable;
}
}
function pausable<T>(notifier: Observable<boolean>): Observable<T> {
return notifier.startWith(false).switchMap((paused) => {
if (paused) {
return Observable.never();
} else {
const source = new Subject();
this.subscribe(source);
return source;
}
});
}
Observable.prototype.pausable = pausable;
skipNextWhen.ts
import { Observable } from 'rxjs/Observable';
import './pausable';
declare module 'rxjs/Observable' {
interface Observable<T> {
skipNextWhen: typeof skipNextWhen;
}
}
function skipNextWhen<T, R>(other: Observable<T>): Observable<R> {
const notifier = Observable.merge(this.map(() => false),
other.map(() => true));
return this.pausable(notifier);
}
Observable.prototype.skipNextWhen = skipNextWhen;
我应该考虑使用更合适的操作员吗?我在当前实现中看到的行为是结果Observable发出一次,然后再也没有 - 即使通知程序Observable永远不会发出。
答案 0 :(得分:4)
我可以想到两个解决方案:
使用.filter()
,.do()
和一些副作用。
这可能更容易理解解决方案,即使它不是“Rx”方式:
function skipNextWhen(other) {
let skipNext = false;
return this.merge(other.do(() => skipNext = true).filter(() => false))
.filter(val => {
const doSkip = skipNext;
skipNext = false;
return !doSkip;
});
}
我正在使用merge()
更新skipNext
,other
的值始终被忽略。
使用.scan()
:
此解决方案没有任何状态变量和副作用。
function skipNextWhen(other) {
const SKIP = 'skip';
return this.merge(other.mapTo(SKIP))
.scan((acc, val) => {
if (acc === SKIP) {
return null;
} else if (val === SKIP) {
return SKIP;
} else {
return val;
}
}, [])
.filter(val => Boolean(val) && val !== SKIP);
}
基本上,当SKIP
到达时,我会立即将其返回,因为它会在acc
运算符的scan()
参数中再次传递,然后被filter()
忽略。< / p>
如果我收到正常值,但之前的值为SKIP
,我会忽略它,只返回null
,后来会过滤掉。
两种解决方案都给出了相同的结果:
Observable.prototype.skipNextWhen = skipNextWhen;
const source = Observable.range(1, 10)
.concatMap(val => Observable.of(val).delay(100));
source
.skipNextWhen(Observable.interval(350))
.subscribe(console.log);
这将打印以下内容:
1
2
3
5
6
8
9
10
请注意,您实际上并没有创建新的运营商。您只需要一个操作员链的快捷方式。例如,当源完成时,您无法取消订阅other
。
答案 1 :(得分:1)
我已经启动了一个(非常)小的我想要的rxjs utils库。它恰好有一个功能可以完全满足您的要求:skipAfter
。从文档中:
source: -1-----2-----3-----4-----5-|
skip$: ----0----------0-0----------
result: -1-----------3-----------5-|