count.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import { Subscriber } from '../Subscriber';
  2. /**
  3. * Counts the number of emissions on the source and emits that number when the
  4. * source completes.
  5. *
  6. * <span class="informal">Tells how many values were emitted, when the source
  7. * completes.</span>
  8. *
  9. * <img src="./img/count.png" width="100%">
  10. *
  11. * `count` transforms an Observable that emits values into an Observable that
  12. * emits a single value that represents the number of values emitted by the
  13. * source Observable. If the source Observable terminates with an error, `count`
  14. * will pass this error notification along without emitting a value first. If
  15. * the source Observable does not terminate at all, `count` will neither emit
  16. * a value nor terminate. This operator takes an optional `predicate` function
  17. * as argument, in which case the output emission will represent the number of
  18. * source values that matched `true` with the `predicate`.
  19. *
  20. * @example <caption>Counts how many seconds have passed before the first click happened</caption>
  21. * var seconds = Rx.Observable.interval(1000);
  22. * var clicks = Rx.Observable.fromEvent(document, 'click');
  23. * var secondsBeforeClick = seconds.takeUntil(clicks);
  24. * var result = secondsBeforeClick.count();
  25. * result.subscribe(x => console.log(x));
  26. *
  27. * @example <caption>Counts how many odd numbers are there between 1 and 7</caption>
  28. * var numbers = Rx.Observable.range(1, 7);
  29. * var result = numbers.count(i => i % 2 === 1);
  30. * result.subscribe(x => console.log(x));
  31. *
  32. * // Results in:
  33. * // 4
  34. *
  35. * @see {@link max}
  36. * @see {@link min}
  37. * @see {@link reduce}
  38. *
  39. * @param {function(value: T, i: number, source: Observable<T>): boolean} [predicate] A
  40. * boolean function to select what values are to be counted. It is provided with
  41. * arguments of:
  42. * - `value`: the value from the source Observable.
  43. * - `index`: the (zero-based) "index" of the value from the source Observable.
  44. * - `source`: the source Observable instance itself.
  45. * @return {Observable} An Observable of one number that represents the count as
  46. * described above.
  47. * @method count
  48. * @owner Observable
  49. */
  50. export function count(predicate) {
  51. return (source) => source.lift(new CountOperator(predicate, source));
  52. }
  53. class CountOperator {
  54. constructor(predicate, source) {
  55. this.predicate = predicate;
  56. this.source = source;
  57. }
  58. call(subscriber, source) {
  59. return source.subscribe(new CountSubscriber(subscriber, this.predicate, this.source));
  60. }
  61. }
  62. /**
  63. * We need this JSDoc comment for affecting ESDoc.
  64. * @ignore
  65. * @extends {Ignored}
  66. */
  67. class CountSubscriber extends Subscriber {
  68. constructor(destination, predicate, source) {
  69. super(destination);
  70. this.predicate = predicate;
  71. this.source = source;
  72. this.count = 0;
  73. this.index = 0;
  74. }
  75. _next(value) {
  76. if (this.predicate) {
  77. this._tryPredicate(value);
  78. }
  79. else {
  80. this.count++;
  81. }
  82. }
  83. _tryPredicate(value) {
  84. let result;
  85. try {
  86. result = this.predicate(value, this.index++, this.source);
  87. }
  88. catch (err) {
  89. this.destination.error(err);
  90. return;
  91. }
  92. if (result) {
  93. this.count++;
  94. }
  95. }
  96. _complete() {
  97. this.destination.next(this.count);
  98. this.destination.complete();
  99. }
  100. }
  101. //# sourceMappingURL=count.js.map