我有两个源可观测值,只要有一个源可观测值发出,我就需要从那里计算一些数据。我正在尝试使用combineAll()
运算符,但它仅在每个源可观察对象首次发射时才发射一个值。
是否有任何类似于combineAll()
的运算符在任何源可观察对象首次发出时发出?如果没有,最清晰的方法是什么?
我尝试过的事情:
const source1$ = service.getSomeData();
const source2$ = service.getOtherData();
combineLatest(
source1$,
source2$
).pipe(
map([source1Data, source2Data] => {
// this code only gets executed when both observables emits for the first time
return source1Data + source2Data;
})
)
答案 0 :(得分:8)
一种方法是在所有来源前面加上this.props.dateFrom
:
startWith
任何可观察到的信号源首次发射时发出的信号?
这似乎是您在寻找combineLatest(
source1$.pipe(startWith(?)),
source2$.pipe(startWith(?)),
)
可以观察到的创建方法,或者仅仅是race(source1$, source2$)
。但这实际上取决于您想做什么。
答案 1 :(得分:1)
如果我理解正确,则需要一种如下图所示的模式:
stream1$ => ------ 1 ------ 12 -----------------------
stream2$ => ------------------------- 30 -------------
result$ => ------ 1 ------ 12 ------ 42 --------------
如果有一个值,则发出该值。如果两者都可用,则发出两者的组合,在这种情况下为简单的总和(12 + 30 = 42);
首先输入流,为了这个示例,我将它们作为主题,因此我们可以手动推送数据:
const stream1$ = new Subject();
const stream2$ = new Subject();
接下来,我们将合并输入,首先通过startWith运算符通过管道传递。这样可以确保CombineLatest产生可观察到的并立即发出-[null, null]
。
const combined$ = combineLatest(
stream1$.pipe(startWith(null)),
stream2$.pipe(startWith(null)),
);
现在,您有一个可观察的对象,该对象总是发出长度为2的数组,其中包含数据的任何组合(在此示例中为数字)和null,如下图所示:
stream1$ | startWith(NULL) => NULL ----------- 1 ----------- 12 ----------------------------
stream2$ | startWith(NULL) => NULL ---------------------------------------- 30 -------------
combined$ [NULL, NULL] --- [1, NULL] --- [12, NULL] --- [12, 30] -------
最后,您可以检查此输出并将其map
转换为所需的格式:两个数字之和(如果两个数字均可用)或第一个数字可用:
const processedCombinations$ = combined$.pipe(
map(([data1, data2]) => {
if (data1 === null) return data2;
if (data2 === null) return data1;
return data1 + data2;
}),
);
结果:
combined$ => [NULL, NULL] --- [1, NULL] --- [12, NULL] --- [12, 30] -------
processedCombinations$ => NULL ----------- 1 ----------- 12 ----------- 42 -------------
一个问题仍然存在:从combined$
发出的第一个值是[null, null]
,导致processedCombinations$
最初发出null
。解决此问题的一种方法是使用skipWhile
将另一个管道链接到processedCombinations$
上:
const final$ = processedCombinations$.pipe(skipWhile((input) => input === null));
结果:
combined$ => [NULL, NULL] --- [1, NULL] --- [12, NULL] --- [12, 30] -------
processedCombinations$ => NULL ----------- 1 ----------- 12 ----------- 42 -------------
final$ => ---------------- 1 ----------- 12 ----------- 42 -------------
另一种-更好的imo-方法是在根据其创建combined$
(现在实际上是processedCombinations$
)之前过滤final$
流:
const combinedFiltered$ = combined$.pipe(
filter(([first, second])=> first !== null || second !== null),
);
const final$ = combinedFiltered$.pipe(
map(([data1, data2]) => {
if (data1 === null) return data2;
if (data2 === null) return data1;
return data1 + data2;
}),
);
相应的图表很好地显示了如何在流层次结构中尽早消除不相关的值:
combined$ => [NULL, NULL] --- [1, NULL] --- [12, NULL] --- [12, 30] -------
combinedFiltered$ => ---------------- [1, NULL] --- [12, NULL] --- [12, 30] -------
final$ => ---------------- 1 ----------- 12 ----------- 42 -------------
可以使用以下代码生成以上图表:
final$.subscribe(console.log);
stream1$.next(1);
// logs: 1
stream1$.next(12);
// logs: 12
stream2$.next(30);
// logs: 42
使用的进口:
import { combineLatest, Subject } from 'rxjs';
import { filter, map, skipWhile, startWith } from 'rxjs/operators';