combineLatest.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. "use strict";
  2. var __extends = (this && this.__extends) || function (d, b) {
  3. for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
  4. function __() { this.constructor = d; }
  5. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  6. };
  7. var ArrayObservable_1 = require('../observable/ArrayObservable');
  8. var isArray_1 = require('../util/isArray');
  9. var OuterSubscriber_1 = require('../OuterSubscriber');
  10. var subscribeToResult_1 = require('../util/subscribeToResult');
  11. var none = {};
  12. /* tslint:enable:max-line-length */
  13. /**
  14. * Combines multiple Observables to create an Observable whose values are
  15. * calculated from the latest values of each of its input Observables.
  16. *
  17. * <span class="informal">Whenever any input Observable emits a value, it
  18. * computes a formula using the latest values from all the inputs, then emits
  19. * the output of that formula.</span>
  20. *
  21. * <img src="./img/combineLatest.png" width="100%">
  22. *
  23. * `combineLatest` combines the values from this Observable with values from
  24. * Observables passed as arguments. This is done by subscribing to each
  25. * Observable, in order, and collecting an array of each of the most recent
  26. * values any time any of the input Observables emits, then either taking that
  27. * array and passing it as arguments to an optional `project` function and
  28. * emitting the return value of that, or just emitting the array of recent
  29. * values directly if there is no `project` function.
  30. *
  31. * @example <caption>Dynamically calculate the Body-Mass Index from an Observable of weight and one for height</caption>
  32. * var weight = Rx.Observable.of(70, 72, 76, 79, 75);
  33. * var height = Rx.Observable.of(1.76, 1.77, 1.78);
  34. * var bmi = weight.combineLatest(height, (w, h) => w / (h * h));
  35. * bmi.subscribe(x => console.log('BMI is ' + x));
  36. *
  37. * // With output to console:
  38. * // BMI is 24.212293388429753
  39. * // BMI is 23.93948099205209
  40. * // BMI is 23.671253629592222
  41. *
  42. * @see {@link combineAll}
  43. * @see {@link merge}
  44. * @see {@link withLatestFrom}
  45. *
  46. * @param {ObservableInput} other An input Observable to combine with the source
  47. * Observable. More than one input Observables may be given as argument.
  48. * @param {function} [project] An optional function to project the values from
  49. * the combined latest values into a new value on the output Observable.
  50. * @return {Observable} An Observable of projected values from the most recent
  51. * values from each input Observable, or an array of the most recent values from
  52. * each input Observable.
  53. * @method combineLatest
  54. * @owner Observable
  55. */
  56. function combineLatest() {
  57. var observables = [];
  58. for (var _i = 0; _i < arguments.length; _i++) {
  59. observables[_i - 0] = arguments[_i];
  60. }
  61. var project = null;
  62. if (typeof observables[observables.length - 1] === 'function') {
  63. project = observables.pop();
  64. }
  65. // if the first and only other argument besides the resultSelector is an array
  66. // assume it's been called with `combineLatest([obs1, obs2, obs3], project)`
  67. if (observables.length === 1 && isArray_1.isArray(observables[0])) {
  68. observables = observables[0].slice();
  69. }
  70. return function (source) { return source.lift.call(new ArrayObservable_1.ArrayObservable([source].concat(observables)), new CombineLatestOperator(project)); };
  71. }
  72. exports.combineLatest = combineLatest;
  73. var CombineLatestOperator = (function () {
  74. function CombineLatestOperator(project) {
  75. this.project = project;
  76. }
  77. CombineLatestOperator.prototype.call = function (subscriber, source) {
  78. return source.subscribe(new CombineLatestSubscriber(subscriber, this.project));
  79. };
  80. return CombineLatestOperator;
  81. }());
  82. exports.CombineLatestOperator = CombineLatestOperator;
  83. /**
  84. * We need this JSDoc comment for affecting ESDoc.
  85. * @ignore
  86. * @extends {Ignored}
  87. */
  88. var CombineLatestSubscriber = (function (_super) {
  89. __extends(CombineLatestSubscriber, _super);
  90. function CombineLatestSubscriber(destination, project) {
  91. _super.call(this, destination);
  92. this.project = project;
  93. this.active = 0;
  94. this.values = [];
  95. this.observables = [];
  96. }
  97. CombineLatestSubscriber.prototype._next = function (observable) {
  98. this.values.push(none);
  99. this.observables.push(observable);
  100. };
  101. CombineLatestSubscriber.prototype._complete = function () {
  102. var observables = this.observables;
  103. var len = observables.length;
  104. if (len === 0) {
  105. this.destination.complete();
  106. }
  107. else {
  108. this.active = len;
  109. this.toRespond = len;
  110. for (var i = 0; i < len; i++) {
  111. var observable = observables[i];
  112. this.add(subscribeToResult_1.subscribeToResult(this, observable, observable, i));
  113. }
  114. }
  115. };
  116. CombineLatestSubscriber.prototype.notifyComplete = function (unused) {
  117. if ((this.active -= 1) === 0) {
  118. this.destination.complete();
  119. }
  120. };
  121. CombineLatestSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) {
  122. var values = this.values;
  123. var oldVal = values[outerIndex];
  124. var toRespond = !this.toRespond
  125. ? 0
  126. : oldVal === none ? --this.toRespond : this.toRespond;
  127. values[outerIndex] = innerValue;
  128. if (toRespond === 0) {
  129. if (this.project) {
  130. this._tryProject(values);
  131. }
  132. else {
  133. this.destination.next(values.slice());
  134. }
  135. }
  136. };
  137. CombineLatestSubscriber.prototype._tryProject = function (values) {
  138. var result;
  139. try {
  140. result = this.project.apply(this, values);
  141. }
  142. catch (err) {
  143. this.destination.error(err);
  144. return;
  145. }
  146. this.destination.next(result);
  147. };
  148. return CombineLatestSubscriber;
  149. }(OuterSubscriber_1.OuterSubscriber));
  150. exports.CombineLatestSubscriber = CombineLatestSubscriber;
  151. //# sourceMappingURL=combineLatest.js.map