esnext.observable.constructor.js 6.1 KB

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