8ad026e834095b4fb8eb4c09d7ce26a3043af003b418d97d40448de8e9562840c8fdc9988cd792c11adf2f0d186244924f237b294dfa7a278af9f577df7eb6 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import { Observable } from '../Observable';
  2. import { SchedulerLike } from '../types';
  3. import { iterator as Symbol_iterator } from '../symbol/iterator';
  4. import { isFunction } from '../util/isFunction';
  5. import { executeSchedule } from '../util/executeSchedule';
  6. /**
  7. * Used in {@link scheduled} to create an observable from an Iterable.
  8. * @param input The iterable to create an observable from
  9. * @param scheduler The scheduler to use
  10. */
  11. export function scheduleIterable<T>(input: Iterable<T>, scheduler: SchedulerLike) {
  12. return new Observable<T>((subscriber) => {
  13. let iterator: Iterator<T, T>;
  14. // Schedule the initial creation of the iterator from
  15. // the iterable. This is so the code in the iterable is
  16. // not called until the scheduled job fires.
  17. executeSchedule(subscriber, scheduler, () => {
  18. // Create the iterator.
  19. iterator = (input as any)[Symbol_iterator]();
  20. executeSchedule(
  21. subscriber,
  22. scheduler,
  23. () => {
  24. let value: T;
  25. let done: boolean | undefined;
  26. try {
  27. // Pull the value out of the iterator
  28. ({ value, done } = iterator.next());
  29. } catch (err) {
  30. // We got an error while pulling from the iterator
  31. subscriber.error(err);
  32. return;
  33. }
  34. if (done) {
  35. // If it is "done" we just complete. This mimics the
  36. // behavior of JavaScript's `for..of` consumption of
  37. // iterables, which will not emit the value from an iterator
  38. // result of `{ done: true: value: 'here' }`.
  39. subscriber.complete();
  40. } else {
  41. // The iterable is not done, emit the value.
  42. subscriber.next(value);
  43. }
  44. },
  45. 0,
  46. true
  47. );
  48. });
  49. // During finalization, if we see this iterator has a `return` method,
  50. // then we know it is a Generator, and not just an Iterator. So we call
  51. // the `return()` function. This will ensure that any `finally { }` blocks
  52. // inside of the generator we can hit will be hit properly.
  53. return () => isFunction(iterator?.return) && iterator.return();
  54. });
  55. }