single.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import { Subscriber } from '../Subscriber';
  2. import { EmptyError } from '../util/EmptyError';
  3. /**
  4. * Returns an Observable that emits the single item emitted by the source Observable that matches a specified
  5. * predicate, if that Observable emits one such item. If the source Observable emits more than one such item or no
  6. * such items, notify of an IllegalArgumentException or NoSuchElementException respectively.
  7. *
  8. * <img src="./img/single.png" width="100%">
  9. *
  10. * @throws {EmptyError} Delivers an EmptyError to the Observer's `error`
  11. * callback if the Observable completes before any `next` notification was sent.
  12. * @param {Function} predicate - A predicate function to evaluate items emitted by the source Observable.
  13. * @return {Observable<T>} An Observable that emits the single item emitted by the source Observable that matches
  14. * the predicate.
  15. .
  16. * @method single
  17. * @owner Observable
  18. */
  19. export function single(predicate) {
  20. return (source) => source.lift(new SingleOperator(predicate, source));
  21. }
  22. class SingleOperator {
  23. constructor(predicate, source) {
  24. this.predicate = predicate;
  25. this.source = source;
  26. }
  27. call(subscriber, source) {
  28. return source.subscribe(new SingleSubscriber(subscriber, this.predicate, this.source));
  29. }
  30. }
  31. /**
  32. * We need this JSDoc comment for affecting ESDoc.
  33. * @ignore
  34. * @extends {Ignored}
  35. */
  36. class SingleSubscriber extends Subscriber {
  37. constructor(destination, predicate, source) {
  38. super(destination);
  39. this.predicate = predicate;
  40. this.source = source;
  41. this.seenValue = false;
  42. this.index = 0;
  43. }
  44. applySingleValue(value) {
  45. if (this.seenValue) {
  46. this.destination.error('Sequence contains more than one element');
  47. }
  48. else {
  49. this.seenValue = true;
  50. this.singleValue = value;
  51. }
  52. }
  53. _next(value) {
  54. const index = this.index++;
  55. if (this.predicate) {
  56. this.tryNext(value, index);
  57. }
  58. else {
  59. this.applySingleValue(value);
  60. }
  61. }
  62. tryNext(value, index) {
  63. try {
  64. if (this.predicate(value, index, this.source)) {
  65. this.applySingleValue(value);
  66. }
  67. }
  68. catch (err) {
  69. this.destination.error(err);
  70. }
  71. }
  72. _complete() {
  73. const destination = this.destination;
  74. if (this.index > 0) {
  75. destination.next(this.seenValue ? this.singleValue : undefined);
  76. destination.complete();
  77. }
  78. else {
  79. destination.error(new EmptyError);
  80. }
  81. }
  82. }
  83. //# sourceMappingURL=single.js.map