combineLatest
函数签名: combineLatest(observables: ...Observable, project: function): Observable
当任意 observable 发出值时,发出每个 observable 的最新值。
此操作符可以既有静态方法,又有实例方法!
当源 observable 完成时,可以使用 combineAll 来应用 combineLatest 以发出 observables !
为什么使用 combineLatest
?
当有多个长期活动的 observables 且它们依靠彼此来进行一些计算或决定时,此操作符是最适合的。示例 3可作为基础示例演示,来自多个按钮的事件被组合在一起,以生成每个按钮的计数和总体总数,RxJS 文档中的 combineLatest 操作符的示例 BMI 计算 也可作为示例。
注意,combineLatest
直到每个 observable 都至少发出一个值后才会发出初始值。这和 withLatestFrom
的行为是一致的,这常常会成为陷阱,既没有输出,也不报错,但是一个(或多个)内部 observables 可能无法正常工作,或者订阅延迟。
最后,如果你只需要 observables 发出一个值,或只需要它们完成前的最新值时,forkJoin
会是更好的选择。
示例
( 示例测试 )
示例 1: 组合3个定时发送的 observables
( StackBlitz | jsBin | jsFiddle )
// RxJS v6+
import { timer, combineLatest } from 'rxjs';
// timerOne 在1秒时发出第一个值,然后每4秒发送一次
const timerOne = timer(1000, 4000);
// timerTwo 在2秒时发出第一个值,然后每4秒发送一次
const timerTwo = timer(2000, 4000);
// timerThree 在3秒时发出第一个值,然后每4秒发送一次
const timerThree = timer(3000, 4000);
// 当一个 timer 发出值时,将每个 timer 的最新值作为一个数组发出
const combined = combineLatest(timerOne, timerTwo, timerThree);
const subscribe = combined.subscribe(latestValues => {
// 从 timerValOne、timerValTwo 和 timerValThree 中获取最新发出的值
const [timerValOne, timerValTwo, timerValThree] = latestValues;
/*
示例:
timerOne first tick: 'Timer One Latest: 1, Timer Two Latest:0, Timer Three Latest: 0
timerTwo first tick: 'Timer One Latest: 1, Timer Two Latest:1, Timer Three Latest: 0
timerThree first tick: 'Timer One Latest: 1, Timer Two Latest:1, Timer Three Latest: 1
*/
console.log(
`Timer One Latest: ${timerValOne},
Timer Two Latest: ${timerValTwo},
Timer Three Latest: ${timerValThree}`
);
}
);
示例 2: 使用 projection 函数的 combineLatest
( StackBlitz | jsBin | jsFiddle )
// RxJS v6+
import { timer, combineLatest } from 'rxjs';
// timerOne 在1秒时发出第一个值,然后每4秒发送一次
const timerOne = timer(1000, 4000);
// timerTwo 在2秒时发出第一个值,然后每4秒发送一次
const timerTwo = timer(2000, 4000);
// timerThree 在3秒时发出第一个值,然后每4秒发送一次
const timerThree = timer(3000, 4000);
// combineLatest 还接收一个可选的 projection 函数
const combinedProject = combineLatest(
timerOne,
timerTwo,
timerThree,
(one, two, three) => {
return `Timer One (Proj) Latest: ${one},
Timer Two (Proj) Latest: ${two},
Timer Three (Proj) Latest: ${three}`;
}
);
// 输出值
const subscribe = combinedProject.subscribe(latestValuesProject =>
console.log(latestValuesProject)
);
示例 3: 组合2个按钮的事件
( StackBlitz | jsBin | jsFiddle )
// RxJS v6+
import { fromEvent, combineLatest } from 'rxjs';
import { mapTo, startWith, scan, tap, map } from 'rxjs/operators';
// 用来设置 HTML 的辅助函数
const setHtml = id => val => (document.getElementById(id).innerHTML = val);
const addOneClick$ = id =>
fromEvent(document.getElementById(id), 'click').pipe(
// 将每次点击映射成1
mapTo(1),
startWith(0),
// 追踪运行中的总数
scan((acc, curr) => acc + curr),
// 为适当的元素设置 HTML
tap(setHtml(`${id}Total`))
);
const combineTotal$ = combineLatest(addOneClick$('red'), addOneClick$('black'))
.pipe(map(([val1, val2]) => val1 + val2))
.subscribe(setHtml('total'));
HTML
<div>
<button id='red'>Red</button>
<button id='black'>Black</button>
</div>
<div>Red: <span id="redTotal"></span> </div>
<div>Black: <span id="blackTotal"></span> </div>
<div>Total: <span id="total"></span> </div>
其他资源
- combineLatest - 官方文档
- 使用 combineLatest 组合流 - John Linquist
- 组合操作符: combineLatest - André Staltz
源码: https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/combineLatest.ts