esnext.observable.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. 'use strict';
  2. // https://github.com/tc39/proposal-observable
  3. var $ = require('../internals/export');
  4. var DESCRIPTORS = require('../internals/descriptors');
  5. var setSpecies = require('../internals/set-species');
  6. var aFunction = require('../internals/a-function');
  7. var anObject = require('../internals/an-object');
  8. var isObject = require('../internals/is-object');
  9. var anInstance = require('../internals/an-instance');
  10. var defineProperty = require('../internals/object-define-property').f;
  11. var createNonEnumerableProperty = require('../internals/create-non-enumerable-property');
  12. var redefineAll = require('../internals/redefine-all');
  13. var getIterator = require('../internals/get-iterator');
  14. var getMethod = require('../internals/get-method');
  15. var iterate = require('../internals/iterate');
  16. var hostReportErrors = require('../internals/host-report-errors');
  17. var wellKnownSymbol = require('../internals/well-known-symbol');
  18. var InternalStateModule = require('../internals/internal-state');
  19. var OBSERVABLE = wellKnownSymbol('observable');
  20. var getInternalState = InternalStateModule.get;
  21. var setInternalState = InternalStateModule.set;
  22. var cleanupSubscription = function (subscriptionState) {
  23. var cleanup = subscriptionState.cleanup;
  24. if (cleanup) {
  25. subscriptionState.cleanup = undefined;
  26. try {
  27. cleanup();
  28. } catch (error) {
  29. hostReportErrors(error);
  30. }
  31. }
  32. };
  33. var subscriptionClosed = function (subscriptionState) {
  34. return subscriptionState.observer === undefined;
  35. };
  36. var close = function (subscriptionState) {
  37. var subscription = subscriptionState.facade;
  38. if (!DESCRIPTORS) {
  39. subscription.closed = true;
  40. var subscriptionObserver = subscriptionState.subscriptionObserver;
  41. if (subscriptionObserver) subscriptionObserver.closed = true;
  42. } subscriptionState.observer = undefined;
  43. };
  44. var Subscription = function (observer, subscriber) {
  45. var subscriptionState = setInternalState(this, {
  46. cleanup: undefined,
  47. observer: anObject(observer),
  48. subscriptionObserver: undefined
  49. });
  50. var start;
  51. if (!DESCRIPTORS) this.closed = false;
  52. try {
  53. if (start = getMethod(observer.start)) start.call(observer, this);
  54. } catch (error) {
  55. hostReportErrors(error);
  56. }
  57. if (subscriptionClosed(subscriptionState)) return;
  58. var subscriptionObserver = subscriptionState.subscriptionObserver = new SubscriptionObserver(this);
  59. try {
  60. var cleanup = subscriber(subscriptionObserver);
  61. var subscription = cleanup;
  62. if (cleanup != null) subscriptionState.cleanup = typeof cleanup.unsubscribe === 'function'
  63. ? function () { subscription.unsubscribe(); }
  64. : aFunction(cleanup);
  65. } catch (error) {
  66. subscriptionObserver.error(error);
  67. return;
  68. } if (subscriptionClosed(subscriptionState)) cleanupSubscription(subscriptionState);
  69. };
  70. Subscription.prototype = redefineAll({}, {
  71. unsubscribe: function unsubscribe() {
  72. var subscriptionState = getInternalState(this);
  73. if (!subscriptionClosed(subscriptionState)) {
  74. close(subscriptionState);
  75. cleanupSubscription(subscriptionState);
  76. }
  77. }
  78. });
  79. if (DESCRIPTORS) defineProperty(Subscription.prototype, 'closed', {
  80. configurable: true,
  81. get: function () {
  82. return subscriptionClosed(getInternalState(this));
  83. }
  84. });
  85. var SubscriptionObserver = function (subscription) {
  86. setInternalState(this, { subscription: subscription });
  87. if (!DESCRIPTORS) this.closed = false;
  88. };
  89. SubscriptionObserver.prototype = redefineAll({}, {
  90. next: function next(value) {
  91. var subscriptionState = getInternalState(getInternalState(this).subscription);
  92. if (!subscriptionClosed(subscriptionState)) {
  93. var observer = subscriptionState.observer;
  94. try {
  95. var nextMethod = getMethod(observer.next);
  96. if (nextMethod) nextMethod.call(observer, value);
  97. } catch (error) {
  98. hostReportErrors(error);
  99. }
  100. }
  101. },
  102. error: function error(value) {
  103. var subscriptionState = getInternalState(getInternalState(this).subscription);
  104. if (!subscriptionClosed(subscriptionState)) {
  105. var observer = subscriptionState.observer;
  106. close(subscriptionState);
  107. try {
  108. var errorMethod = getMethod(observer.error);
  109. if (errorMethod) errorMethod.call(observer, value);
  110. else hostReportErrors(value);
  111. } catch (err) {
  112. hostReportErrors(err);
  113. } cleanupSubscription(subscriptionState);
  114. }
  115. },
  116. complete: function complete() {
  117. var subscriptionState = getInternalState(getInternalState(this).subscription);
  118. if (!subscriptionClosed(subscriptionState)) {
  119. var observer = subscriptionState.observer;
  120. close(subscriptionState);
  121. try {
  122. var completeMethod = getMethod(observer.complete);
  123. if (completeMethod) completeMethod.call(observer);
  124. } catch (error) {
  125. hostReportErrors(error);
  126. } cleanupSubscription(subscriptionState);
  127. }
  128. }
  129. });
  130. if (DESCRIPTORS) defineProperty(SubscriptionObserver.prototype, 'closed', {
  131. configurable: true,
  132. get: function () {
  133. return subscriptionClosed(getInternalState(getInternalState(this).subscription));
  134. }
  135. });
  136. var $Observable = function Observable(subscriber) {
  137. anInstance(this, $Observable, 'Observable');
  138. setInternalState(this, { subscriber: aFunction(subscriber) });
  139. };
  140. redefineAll($Observable.prototype, {
  141. subscribe: function subscribe(observer) {
  142. var length = arguments.length;
  143. return new Subscription(typeof observer === 'function' ? {
  144. next: observer,
  145. error: length > 1 ? arguments[1] : undefined,
  146. complete: length > 2 ? arguments[2] : undefined
  147. } : isObject(observer) ? observer : {}, getInternalState(this).subscriber);
  148. }
  149. });
  150. redefineAll($Observable, {
  151. from: function from(x) {
  152. var C = typeof this === 'function' ? this : $Observable;
  153. var observableMethod = getMethod(anObject(x)[OBSERVABLE]);
  154. if (observableMethod) {
  155. var observable = anObject(observableMethod.call(x));
  156. return observable.constructor === C ? observable : new C(function (observer) {
  157. return observable.subscribe(observer);
  158. });
  159. }
  160. var iterator = getIterator(x);
  161. return new C(function (observer) {
  162. iterate(iterator, function (it, stop) {
  163. observer.next(it);
  164. if (observer.closed) return stop();
  165. }, { IS_ITERATOR: true, INTERRUPTED: true });
  166. observer.complete();
  167. });
  168. },
  169. of: function of() {
  170. var C = typeof this === 'function' ? this : $Observable;
  171. var length = arguments.length;
  172. var items = new Array(length);
  173. var index = 0;
  174. while (index < length) items[index] = arguments[index++];
  175. return new C(function (observer) {
  176. for (var i = 0; i < length; i++) {
  177. observer.next(items[i]);
  178. if (observer.closed) return;
  179. } observer.complete();
  180. });
  181. }
  182. });
  183. createNonEnumerableProperty($Observable.prototype, OBSERVABLE, function () { return this; });
  184. $({ global: true }, {
  185. Observable: $Observable
  186. });
  187. setSpecies('Observable');