UNPKG

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