last.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { Subscriber } from '../Subscriber';
  2. import { EmptyError } from '../util/EmptyError';
  3. /* tslint:enable:max-line-length */
  4. /**
  5. * Returns an Observable that emits only the last item emitted by the source Observable.
  6. * It optionally takes a predicate function as a parameter, in which case, rather than emitting
  7. * the last item from the source Observable, the resulting Observable will emit the last item
  8. * from the source Observable that satisfies the predicate.
  9. *
  10. * <img src="./img/last.png" width="100%">
  11. *
  12. * @throws {EmptyError} Delivers an EmptyError to the Observer's `error`
  13. * callback if the Observable completes before any `next` notification was sent.
  14. * @param {function} predicate - The condition any source emitted item has to satisfy.
  15. * @return {Observable} An Observable that emits only the last item satisfying the given condition
  16. * from the source, or an NoSuchElementException if no such items are emitted.
  17. * @throws - Throws if no items that match the predicate are emitted by the source Observable.
  18. * @method last
  19. * @owner Observable
  20. */
  21. export function last(predicate, resultSelector, defaultValue) {
  22. return (source) => source.lift(new LastOperator(predicate, resultSelector, defaultValue, source));
  23. }
  24. class LastOperator {
  25. constructor(predicate, resultSelector, defaultValue, source) {
  26. this.predicate = predicate;
  27. this.resultSelector = resultSelector;
  28. this.defaultValue = defaultValue;
  29. this.source = source;
  30. }
  31. call(observer, source) {
  32. return source.subscribe(new LastSubscriber(observer, this.predicate, this.resultSelector, this.defaultValue, this.source));
  33. }
  34. }
  35. /**
  36. * We need this JSDoc comment for affecting ESDoc.
  37. * @ignore
  38. * @extends {Ignored}
  39. */
  40. class LastSubscriber extends Subscriber {
  41. constructor(destination, predicate, resultSelector, defaultValue, source) {
  42. super(destination);
  43. this.predicate = predicate;
  44. this.resultSelector = resultSelector;
  45. this.defaultValue = defaultValue;
  46. this.source = source;
  47. this.hasValue = false;
  48. this.index = 0;
  49. if (typeof defaultValue !== 'undefined') {
  50. this.lastValue = defaultValue;
  51. this.hasValue = true;
  52. }
  53. }
  54. _next(value) {
  55. const index = this.index++;
  56. if (this.predicate) {
  57. this._tryPredicate(value, index);
  58. }
  59. else {
  60. if (this.resultSelector) {
  61. this._tryResultSelector(value, index);
  62. return;
  63. }
  64. this.lastValue = value;
  65. this.hasValue = true;
  66. }
  67. }
  68. _tryPredicate(value, index) {
  69. let result;
  70. try {
  71. result = this.predicate(value, index, this.source);
  72. }
  73. catch (err) {
  74. this.destination.error(err);
  75. return;
  76. }
  77. if (result) {
  78. if (this.resultSelector) {
  79. this._tryResultSelector(value, index);
  80. return;
  81. }
  82. this.lastValue = value;
  83. this.hasValue = true;
  84. }
  85. }
  86. _tryResultSelector(value, index) {
  87. let result;
  88. try {
  89. result = this.resultSelector(value, index);
  90. }
  91. catch (err) {
  92. this.destination.error(err);
  93. return;
  94. }
  95. this.lastValue = result;
  96. this.hasValue = true;
  97. }
  98. _complete() {
  99. const destination = this.destination;
  100. if (this.hasValue) {
  101. destination.next(this.lastValue);
  102. destination.complete();
  103. }
  104. else {
  105. destination.error(new EmptyError);
  106. }
  107. }
  108. }
  109. //# sourceMappingURL=last.js.map