combineLatest

签名: combineLatest(observables: ...Observable, project: function): Observable

当任意 observable 发出值时,发出每个 observable 的最新值。


:bulb: 此操作符可以既有静态方法,又有实例方法!

:bulb: 当源 observable 完成时,可以使用 combineAll 来应用 combineLatest 以发出 observables !


为什么使用 combineLatest

当有多个长期活动的 observables 且它们依靠彼此来进行一些计算或决定时,此操作符是最适合的。示例 3可作为基础示例演示,来自多个按钮的事件被组合在一起,以生成每个按钮的计数和总体总数,RxJS 文档中的 combineLatest 操作符的示例 BMI 计算 也可作为示例。

注意,combineLatest 直到每个 observable 都至少发出一个值后才会发出初始值。这和 withLatestFrom 的行为是一致的,这常常会成为陷阱,既没有输出,也不报错,但是一个(或多个)内部 observables 可能无法正常工作,或者订阅延迟。

最后,如果你只需要 observables 发出一个值,或只需要它们完成前的最新值时,forkJoin 会是更好的选择。

combineLatest - 图3

示例

( 示例测试 )

示例 1: 组合3个定时发送的 observables

( StackBlitz |
jsBin |
jsFiddle )

  1. import { timer } from 'rxjs/observable/timer';
  2. import { combineLatest } from 'rxjs/observable/combineLatest';
  3. // timerOne 在1秒时发出第一个值,然后每4秒发送一次
  4. const timerOne = timer(1000, 4000);
  5. // timerTwo 在2秒时发出第一个值,然后每4秒发送一次
  6. const timerTwo = timer(2000, 4000);
  7. // timerThree 在3秒时发出第一个值,然后每4秒发送一次
  8. const timerThree = timer(3000, 4000);
  9. // 当一个 timer 发出值时,将每个 timer 的最新值作为一个数组发出
  10. const combined = combineLatest(timerOne, timerTwo, timerThree);
  11. const subscribe = combined.subscribe(latestValues => {
  12. // 从 timerValOne、timerValTwo 和 timerValThree 中获取最新发出的值
  13. const [timerValOne, timerValTwo, timerValThree] = latestValues;
  14. /*
  15. 示例:
  16. timerOne first tick: 'Timer One Latest: 1, Timer Two Latest:0, Timer Three Latest: 0
  17. timerTwo first tick: 'Timer One Latest: 1, Timer Two Latest:1, Timer Three Latest: 0
  18. timerThree first tick: 'Timer One Latest: 1, Timer Two Latest:1, Timer Three Latest: 1
  19. */
  20. console.log(
  21. `Timer One Latest: ${timerValOne},
  22. Timer Two Latest: ${timerValTwo},
  23. Timer Three Latest: ${timerValThree}`
  24. );
  25. }
  26. );
示例 2: 使用 projection 函数的 combineLatest

( StackBlitz |
jsBin |
jsFiddle )

  1. import { timer } from 'rxjs/observable/timer';
  2. import { combineLatest } from 'rxjs/observable/combineLatest';
  3. // timerOne 在1秒时发出第一个值,然后每4秒发送一次
  4. const timerOne = timer(1000, 4000);
  5. // timerTwo 在2秒时发出第一个值,然后每4秒发送一次
  6. const timerTwo = timer(2000, 4000);
  7. // timerThree 在3秒时发出第一个值,然后每4秒发送一次
  8. const timerThree = timer(3000, 4000);
  9. // combineLatest 还接收一个可选的 projection 函数
  10. const combinedProject = combineLatest(
  11. timerOne,
  12. timerTwo,
  13. timerThree,
  14. (one, two, three) => {
  15. return `Timer One (Proj) Latest: ${one},
  16. Timer Two (Proj) Latest: ${two},
  17. Timer Three (Proj) Latest: ${three}`;
  18. }
  19. );
  20. // 输出值
  21. const subscribe = combinedProject.subscribe(latestValuesProject =>
  22. console.log(latestValuesProject)
  23. );
示例 3: 组合2个按钮的事件

( StackBlitz |
jsBin |
jsFiddle )

  1. import { mapTo, startWith, scan, tap, map } from 'rxjs/operators';
  2. import { fromEvent } from 'rxjs/observable/fromEvent';
  3. import { combineLatest } from 'rxjs/observable/combineLatest';
  4. // 用来设置 HTML 的辅助函数
  5. const setHtml = id => val => (document.getElementById(id).innerHTML = val);
  6. const addOneClick$ = id =>
  7. fromEvent(document.getElementById(id), 'click').pipe(
  8. // 将每次点击映射成1
  9. mapTo(1),
  10. startWith(0),
  11. // 追踪运行中的总数
  12. scan((acc, curr) => acc + curr),
  13. // 为适当的元素设置 HTML
  14. tap(setHtml(`${id}Total`))
  15. );
  16. const combineTotal$ = combineLatest(addOneClick$('red'), addOneClick$('black'))
  17. .pipe(map(([val1, val2]) => val1 + val2))
  18. .subscribe(setHtml('total'));
HTML
  1. <div>
  2. <button id='red'>Red</button>
  3. <button id='black'>Black</button>
  4. </div>
  5. <div>Red: <span id="redTotal"></span> </div>
  6. <div>Black: <span id="blackTotal"></span> </div>
  7. <div>Total: <span id="total"></span> </div>

其他资源


:file_folder: 源码: https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/combineLatest.ts