UNPKG

9.78 kBJavaScriptView Raw
1'use strict';
2var $ = require('../internals/export');
3var IS_PURE = require('../internals/is-pure');
4var IS_NODE = require('../internals/engine-is-node');
5var global = require('../internals/global');
6var call = require('../internals/function-call');
7var defineBuiltIn = require('../internals/define-built-in');
8var setPrototypeOf = require('../internals/object-set-prototype-of');
9var setToStringTag = require('../internals/set-to-string-tag');
10var setSpecies = require('../internals/set-species');
11var aCallable = require('../internals/a-callable');
12var isCallable = require('../internals/is-callable');
13var isObject = require('../internals/is-object');
14var anInstance = require('../internals/an-instance');
15var speciesConstructor = require('../internals/species-constructor');
16var task = require('../internals/task').set;
17var microtask = require('../internals/microtask');
18var hostReportErrors = require('../internals/host-report-errors');
19var perform = require('../internals/perform');
20var Queue = require('../internals/queue');
21var InternalStateModule = require('../internals/internal-state');
22var NativePromiseConstructor = require('../internals/promise-native-constructor');
23var PromiseConstructorDetection = require('../internals/promise-constructor-detection');
24var newPromiseCapabilityModule = require('../internals/new-promise-capability');
25
26var PROMISE = 'Promise';
27var FORCED_PROMISE_CONSTRUCTOR = PromiseConstructorDetection.CONSTRUCTOR;
28var NATIVE_PROMISE_REJECTION_EVENT = PromiseConstructorDetection.REJECTION_EVENT;
29var NATIVE_PROMISE_SUBCLASSING = PromiseConstructorDetection.SUBCLASSING;
30var getInternalPromiseState = InternalStateModule.getterFor(PROMISE);
31var setInternalState = InternalStateModule.set;
32var NativePromisePrototype = NativePromiseConstructor && NativePromiseConstructor.prototype;
33var PromiseConstructor = NativePromiseConstructor;
34var PromisePrototype = NativePromisePrototype;
35var TypeError = global.TypeError;
36var document = global.document;
37var process = global.process;
38var newPromiseCapability = newPromiseCapabilityModule.f;
39var newGenericPromiseCapability = newPromiseCapability;
40
41var DISPATCH_EVENT = !!(document && document.createEvent && global.dispatchEvent);
42var UNHANDLED_REJECTION = 'unhandledrejection';
43var REJECTION_HANDLED = 'rejectionhandled';
44var PENDING = 0;
45var FULFILLED = 1;
46var REJECTED = 2;
47var HANDLED = 1;
48var UNHANDLED = 2;
49
50var Internal, OwnPromiseCapability, PromiseWrapper, nativeThen;
51
52// helpers
53var isThenable = function (it) {
54 var then;
55 return isObject(it) && isCallable(then = it.then) ? then : false;
56};
57
58var callReaction = function (reaction, state) {
59 var value = state.value;
60 var ok = state.state === FULFILLED;
61 var handler = ok ? reaction.ok : reaction.fail;
62 var resolve = reaction.resolve;
63 var reject = reaction.reject;
64 var domain = reaction.domain;
65 var result, then, exited;
66 try {
67 if (handler) {
68 if (!ok) {
69 if (state.rejection === UNHANDLED) onHandleUnhandled(state);
70 state.rejection = HANDLED;
71 }
72 if (handler === true) result = value;
73 else {
74 if (domain) domain.enter();
75 result = handler(value); // can throw
76 if (domain) {
77 domain.exit();
78 exited = true;
79 }
80 }
81 if (result === reaction.promise) {
82 reject(new TypeError('Promise-chain cycle'));
83 } else if (then = isThenable(result)) {
84 call(then, result, resolve, reject);
85 } else resolve(result);
86 } else reject(value);
87 } catch (error) {
88 if (domain && !exited) domain.exit();
89 reject(error);
90 }
91};
92
93var notify = function (state, isReject) {
94 if (state.notified) return;
95 state.notified = true;
96 microtask(function () {
97 var reactions = state.reactions;
98 var reaction;
99 while (reaction = reactions.get()) {
100 callReaction(reaction, state);
101 }
102 state.notified = false;
103 if (isReject && !state.rejection) onUnhandled(state);
104 });
105};
106
107var dispatchEvent = function (name, promise, reason) {
108 var event, handler;
109 if (DISPATCH_EVENT) {
110 event = document.createEvent('Event');
111 event.promise = promise;
112 event.reason = reason;
113 event.initEvent(name, false, true);
114 global.dispatchEvent(event);
115 } else event = { promise: promise, reason: reason };
116 if (!NATIVE_PROMISE_REJECTION_EVENT && (handler = global['on' + name])) handler(event);
117 else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
118};
119
120var onUnhandled = function (state) {
121 call(task, global, function () {
122 var promise = state.facade;
123 var value = state.value;
124 var IS_UNHANDLED = isUnhandled(state);
125 var result;
126 if (IS_UNHANDLED) {
127 result = perform(function () {
128 if (IS_NODE) {
129 process.emit('unhandledRejection', value, promise);
130 } else dispatchEvent(UNHANDLED_REJECTION, promise, value);
131 });
132 // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
133 state.rejection = IS_NODE || isUnhandled(state) ? UNHANDLED : HANDLED;
134 if (result.error) throw result.value;
135 }
136 });
137};
138
139var isUnhandled = function (state) {
140 return state.rejection !== HANDLED && !state.parent;
141};
142
143var onHandleUnhandled = function (state) {
144 call(task, global, function () {
145 var promise = state.facade;
146 if (IS_NODE) {
147 process.emit('rejectionHandled', promise);
148 } else dispatchEvent(REJECTION_HANDLED, promise, state.value);
149 });
150};
151
152var bind = function (fn, state, unwrap) {
153 return function (value) {
154 fn(state, value, unwrap);
155 };
156};
157
158var internalReject = function (state, value, unwrap) {
159 if (state.done) return;
160 state.done = true;
161 if (unwrap) state = unwrap;
162 state.value = value;
163 state.state = REJECTED;
164 notify(state, true);
165};
166
167var internalResolve = function (state, value, unwrap) {
168 if (state.done) return;
169 state.done = true;
170 if (unwrap) state = unwrap;
171 try {
172 if (state.facade === value) throw new TypeError("Promise can't be resolved itself");
173 var then = isThenable(value);
174 if (then) {
175 microtask(function () {
176 var wrapper = { done: false };
177 try {
178 call(then, value,
179 bind(internalResolve, wrapper, state),
180 bind(internalReject, wrapper, state)
181 );
182 } catch (error) {
183 internalReject(wrapper, error, state);
184 }
185 });
186 } else {
187 state.value = value;
188 state.state = FULFILLED;
189 notify(state, false);
190 }
191 } catch (error) {
192 internalReject({ done: false }, error, state);
193 }
194};
195
196// constructor polyfill
197if (FORCED_PROMISE_CONSTRUCTOR) {
198 // 25.4.3.1 Promise(executor)
199 PromiseConstructor = function Promise(executor) {
200 anInstance(this, PromisePrototype);
201 aCallable(executor);
202 call(Internal, this);
203 var state = getInternalPromiseState(this);
204 try {
205 executor(bind(internalResolve, state), bind(internalReject, state));
206 } catch (error) {
207 internalReject(state, error);
208 }
209 };
210
211 PromisePrototype = PromiseConstructor.prototype;
212
213 // eslint-disable-next-line no-unused-vars -- required for `.length`
214 Internal = function Promise(executor) {
215 setInternalState(this, {
216 type: PROMISE,
217 done: false,
218 notified: false,
219 parent: false,
220 reactions: new Queue(),
221 rejection: false,
222 state: PENDING,
223 value: undefined
224 });
225 };
226
227 // `Promise.prototype.then` method
228 // https://tc39.es/ecma262/#sec-promise.prototype.then
229 Internal.prototype = defineBuiltIn(PromisePrototype, 'then', function then(onFulfilled, onRejected) {
230 var state = getInternalPromiseState(this);
231 var reaction = newPromiseCapability(speciesConstructor(this, PromiseConstructor));
232 state.parent = true;
233 reaction.ok = isCallable(onFulfilled) ? onFulfilled : true;
234 reaction.fail = isCallable(onRejected) && onRejected;
235 reaction.domain = IS_NODE ? process.domain : undefined;
236 if (state.state === PENDING) state.reactions.add(reaction);
237 else microtask(function () {
238 callReaction(reaction, state);
239 });
240 return reaction.promise;
241 });
242
243 OwnPromiseCapability = function () {
244 var promise = new Internal();
245 var state = getInternalPromiseState(promise);
246 this.promise = promise;
247 this.resolve = bind(internalResolve, state);
248 this.reject = bind(internalReject, state);
249 };
250
251 newPromiseCapabilityModule.f = newPromiseCapability = function (C) {
252 return C === PromiseConstructor || C === PromiseWrapper
253 ? new OwnPromiseCapability(C)
254 : newGenericPromiseCapability(C);
255 };
256
257 if (!IS_PURE && isCallable(NativePromiseConstructor) && NativePromisePrototype !== Object.prototype) {
258 nativeThen = NativePromisePrototype.then;
259
260 if (!NATIVE_PROMISE_SUBCLASSING) {
261 // make `Promise#then` return a polyfilled `Promise` for native promise-based APIs
262 defineBuiltIn(NativePromisePrototype, 'then', function then(onFulfilled, onRejected) {
263 var that = this;
264 return new PromiseConstructor(function (resolve, reject) {
265 call(nativeThen, that, resolve, reject);
266 }).then(onFulfilled, onRejected);
267 // https://github.com/zloirock/core-js/issues/640
268 }, { unsafe: true });
269 }
270
271 // make `.constructor === Promise` work for native promise-based APIs
272 try {
273 delete NativePromisePrototype.constructor;
274 } catch (error) { /* empty */ }
275
276 // make `instanceof Promise` work for native promise-based APIs
277 if (setPrototypeOf) {
278 setPrototypeOf(NativePromisePrototype, PromisePrototype);
279 }
280 }
281}
282
283$({ global: true, constructor: true, wrap: true, forced: FORCED_PROMISE_CONSTRUCTOR }, {
284 Promise: PromiseConstructor
285});
286
287setToStringTag(PromiseConstructor, PROMISE, false, true);
288setSpecies(PROMISE);