esnext.observable.constructor.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. 'use strict';
  2. // https://github.com/tc39/proposal-observable
  3. var $ = require('../internals/export');
  4. var call = require('../internals/function-call');
  5. var DESCRIPTORS = require('../internals/descriptors');
  6. var setSpecies = require('../internals/set-species');
  7. var aCallable = require('../internals/a-callable');
  8. var anObject = require('../internals/an-object');
  9. var anInstance = require('../internals/an-instance');
  10. var isCallable = require('../internals/is-callable');
  11. var isNullOrUndefined = require('../internals/is-null-or-undefined');
  12. var isObject = require('../internals/is-object');
  13. var getMethod = require('../internals/get-method');
  14. var defineBuiltIn = require('../internals/define-built-in');
  15. var defineBuiltIns = require('../internals/define-built-ins');
  16. var defineBuiltInAccessor = require('../internals/define-built-in-accessor');
  17. var hostReportErrors = require('../internals/host-report-errors');
  18. var wellKnownSymbol = require('../internals/well-known-symbol');
  19. var InternalStateModule = require('../internals/internal-state');
  20. var OBSERVABLE_FORCED = require('../internals/observable-forced');
  21. var $$OBSERVABLE = wellKnownSymbol('observable');
  22. var OBSERVABLE = 'Observable';
  23. var SUBSCRIPTION = 'Subscription';
  24. var SUBSCRIPTION_OBSERVER = 'SubscriptionObserver';
  25. var getterFor = InternalStateModule.getterFor;
  26. var setInternalState = InternalStateModule.set;
  27. var getObservableInternalState = getterFor(OBSERVABLE);
  28. var getSubscriptionInternalState = getterFor(SUBSCRIPTION);
  29. var getSubscriptionObserverInternalState = getterFor(SUBSCRIPTION_OBSERVER);
  30. var SubscriptionState = function (observer) {
  31. this.observer = anObject(observer);
  32. this.cleanup = undefined;
  33. this.subscriptionObserver = undefined;
  34. };
  35. SubscriptionState.prototype = {
  36. type: SUBSCRIPTION,
  37. clean: function () {
  38. var cleanup = this.cleanup;
  39. if (cleanup) {
  40. this.cleanup = undefined;
  41. try {
  42. cleanup();
  43. } catch (error) {
  44. hostReportErrors(error);
  45. }
  46. }
  47. },
  48. close: function () {
  49. if (!DESCRIPTORS) {
  50. var subscription = this.facade;
  51. var subscriptionObserver = this.subscriptionObserver;
  52. subscription.closed = true;
  53. if (subscriptionObserver) subscriptionObserver.closed = true;
  54. } this.observer = undefined;
  55. },
  56. isClosed: function () {
  57. return this.observer === undefined;
  58. }
  59. };
  60. var Subscription = function (observer, subscriber) {
  61. var subscriptionState = setInternalState(this, new SubscriptionState(observer));
  62. var start;
  63. if (!DESCRIPTORS) this.closed = false;
  64. try {
  65. if (start = getMethod(observer, 'start')) call(start, observer, this);
  66. } catch (error) {
  67. hostReportErrors(error);
  68. }
  69. if (subscriptionState.isClosed()) return;
  70. var subscriptionObserver = subscriptionState.subscriptionObserver = new SubscriptionObserver(subscriptionState);
  71. try {
  72. var cleanup = subscriber(subscriptionObserver);
  73. var subscription = cleanup;
  74. if (!isNullOrUndefined(cleanup)) subscriptionState.cleanup = isCallable(cleanup.unsubscribe)
  75. ? function () { subscription.unsubscribe(); }
  76. : aCallable(cleanup);
  77. } catch (error) {
  78. subscriptionObserver.error(error);
  79. return;
  80. } if (subscriptionState.isClosed()) subscriptionState.clean();
  81. };
  82. Subscription.prototype = defineBuiltIns({}, {
  83. unsubscribe: function unsubscribe() {
  84. var subscriptionState = getSubscriptionInternalState(this);
  85. if (!subscriptionState.isClosed()) {
  86. subscriptionState.close();
  87. subscriptionState.clean();
  88. }
  89. }
  90. });
  91. if (DESCRIPTORS) defineBuiltInAccessor(Subscription.prototype, 'closed', {
  92. configurable: true,
  93. get: function closed() {
  94. return getSubscriptionInternalState(this).isClosed();
  95. }
  96. });
  97. var SubscriptionObserver = function (subscriptionState) {
  98. setInternalState(this, {
  99. type: SUBSCRIPTION_OBSERVER,
  100. subscriptionState: subscriptionState
  101. });
  102. if (!DESCRIPTORS) this.closed = false;
  103. };
  104. SubscriptionObserver.prototype = defineBuiltIns({}, {
  105. next: function next(value) {
  106. var subscriptionState = getSubscriptionObserverInternalState(this).subscriptionState;
  107. if (!subscriptionState.isClosed()) {
  108. var observer = subscriptionState.observer;
  109. try {
  110. var nextMethod = getMethod(observer, 'next');
  111. if (nextMethod) call(nextMethod, observer, value);
  112. } catch (error) {
  113. hostReportErrors(error);
  114. }
  115. }
  116. },
  117. error: function error(value) {
  118. var subscriptionState = getSubscriptionObserverInternalState(this).subscriptionState;
  119. if (!subscriptionState.isClosed()) {
  120. var observer = subscriptionState.observer;
  121. subscriptionState.close();
  122. try {
  123. var errorMethod = getMethod(observer, 'error');
  124. if (errorMethod) call(errorMethod, observer, value);
  125. else hostReportErrors(value);
  126. } catch (err) {
  127. hostReportErrors(err);
  128. } subscriptionState.clean();
  129. }
  130. },
  131. complete: function complete() {
  132. var subscriptionState = getSubscriptionObserverInternalState(this).subscriptionState;
  133. if (!subscriptionState.isClosed()) {
  134. var observer = subscriptionState.observer;
  135. subscriptionState.close();
  136. try {
  137. var completeMethod = getMethod(observer, 'complete');
  138. if (completeMethod) call(completeMethod, observer);
  139. } catch (error) {
  140. hostReportErrors(error);
  141. } subscriptionState.clean();
  142. }
  143. }
  144. });
  145. if (DESCRIPTORS) defineBuiltInAccessor(SubscriptionObserver.prototype, 'closed', {
  146. configurable: true,
  147. get: function closed() {
  148. return getSubscriptionObserverInternalState(this).subscriptionState.isClosed();
  149. }
  150. });
  151. var $Observable = function Observable(subscriber) {
  152. anInstance(this, ObservablePrototype);
  153. setInternalState(this, {
  154. type: OBSERVABLE,
  155. subscriber: aCallable(subscriber)
  156. });
  157. };
  158. var ObservablePrototype = $Observable.prototype;
  159. defineBuiltIns(ObservablePrototype, {
  160. subscribe: function subscribe(observer) {
  161. var length = arguments.length;
  162. return new Subscription(isCallable(observer) ? {
  163. next: observer,
  164. error: length > 1 ? arguments[1] : undefined,
  165. complete: length > 2 ? arguments[2] : undefined
  166. } : isObject(observer) ? observer : {}, getObservableInternalState(this).subscriber);
  167. }
  168. });
  169. defineBuiltIn(ObservablePrototype, $$OBSERVABLE, function () { return this; });
  170. $({ global: true, constructor: true, forced: OBSERVABLE_FORCED }, {
  171. Observable: $Observable
  172. });
  173. setSpecies(OBSERVABLE);