我有两个源可观察量。 我想合并两个源可观察对象,但只要其中一个源可观察对象完成,合并的可观察对象就会完成。
期望的行为:
Source 1: ---1--------3--4-----------------------------x
Source 2: -------2----------e
"merged" ---1---2----3--4--ex
如果其中一个源出现错误,则错误应传播到合并的observable:
Source 1: ---1--------3--4-----------------------------x
Source 2: -------2----------x
"merged" ---1---2----3--4-----------------------------x
"合并"运算符仅在两个源完成时完成合并流:
{{1}}
我如何实现我想要的行为?
答案 0 :(得分:10)
您需要使用元数据,每个observable的信息。为此,请在每个流上使用materialize()
运算符,并在合并流上使用dematerialize()
来实际发出数据。
Observable.merge( observableA.materialize(),
observableB.materialize() )
.takeWhile( notification -> notification.hasValue() )
.dematerialize()
.subscribe( ... );
这将合并两个observable,直到其中一个完成或发出错误。
答案 1 :(得分:1)
我确定希望其他人用更优雅的方法回答,但这很有效。
我认为您必须使用其中一个take
运算符。当一个源完成时,您可以完成所有源:
const a = Rx.Observable.interval(1000).take(3).map(x => `a${x}`);
const b = Rx.Observable.interval(800).take(6).map(x => `b${x}`);
Rx.Observable.merge(a.takeUntil(b.last()), b.takeUntil(a.last()))
.subscribe(
x => { console.log('next', x); },
null,
() => { console.log('complete'); }
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.5/Rx.min.js"></script>
或者可读性较差但可扩展性较强的版本:
function merge(...obs) {
return Rx.Observable.merge(...obs.map(x => x.takeUntil(Rx.Observable.race(obs.filter(y => y !== x).map(z => z.last())))));
}
const a = Rx.Observable.interval(1000).take(3).map(x => `a${x}`);
const b = Rx.Observable.interval(800).take(6).map(x => `b${x}`);
merge(a, b)
.subscribe(
x => { console.log('next', x); },
null,
() => { console.log('complete'); }
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.5/Rx.min.js"></script>
以下是错误传播的说明:
function merge(...obs) {
return Rx.Observable.merge(...obs.map(x => x.takeUntil(Rx.Observable.race(obs.filter(y => y !== x).map(z => z.last())))));
}
const a = Rx.Observable.interval(1000).take(3).map(x => `a${x}`);
const b = Rx.Observable.interval(800).take(6).map(x => `b${x}`);
const c = Rx.Observable.timer(2200).map(x => { throw 'oops!'; });
merge(a, b, c)
.subscribe(
x => { console.log('next', x); },
x => { console.log('error', x); },
() => { console.log('complete'); }
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.5/Rx.min.js"></script>
在合并上使用takeUntil
外部是很棘手的,因为你会丢失最后一个发射值。
答案 2 :(得分:1)
当一个observable完成时,它不会发出一个值,但我们可以concat
使用另一个&#39;信号&#39;可观察的,发出单个值。然后,我们可以观察信号&#39;使用takeWhile
运算符可观察到的值。
当然,您必须确保发出“信号”信号。可观察的发射值不是可以被合并的可观察者发出的值 - 如果takeWhile
谓词通过引用进行比较,则空对象就足够了。
以下是一个例子:
const obs1$ = Rx.Observable.interval(1000)
.map(x => `obs1: ${x}`)
.take(5);
const obs2$ = Rx.Observable.interval(300)
.map(x => `obs2: ${x}`)
.take(9);
const signalFinishMessage = {};
const signalFinish$ = Rx.Observable.of(signalFinishMessage);
Rx.Observable.merge(obs1$.concat(signalFinish$), obs2$.concat(signalFinish$))
.takeWhile(x => x !== signalFinishMessage)
.subscribe(
x => console.log(x),
err => console.log('received error:', err),
() => console.log('complete')
);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.5/Rx.min.js"></script>
&#13;
错误也会传播:
const obs1$ = Rx.Observable.interval(1000)
.map(x => `obs1: ${x}`)
.take(5);
const obs2$ = Rx.Observable.interval(300)
.map(x => `obs2: ${x}`)
.take(9)
.concat(Rx.Observable.throw(`the world's about to end`));
const signalFinishMessage = {};
const signalFinish$ = Rx.Observable.of(signalFinishMessage);
Rx.Observable.merge(obs1$.concat(signalFinish$), obs2$.concat(signalFinish$))
.takeWhile(x => x !== signalFinishMessage)
.subscribe(
x => console.log(x),
err => console.log('received error:', err),
() => console.log('complete')
);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.5/Rx.min.js"></script>
&#13;
答案 3 :(得分:1)
我最终自己动手了:
import { Observable } from 'rxjs';
export function whileAll<T>(...observables: Observable<T>[]): Observable<T> {
return new Observable<T>(function (observer) {
if (observables.length === 0)
observer.complete();
else {
const next = observer.next.bind(observer);
const error = observer.error.bind(observer);
const complete = observer.complete.bind(observer);
for (let i = 0; i < observables.length; i++)
observer.add(observables[i].subscribe(next, error, complete));
}
});
}