UNPKG

12.9 kBJavaScriptView Raw
1'use strict';
2var $ = require('../internals/export');
3var IS_PURE = require('../internals/is-pure');
4var global = require('../internals/global');
5var getBuiltIn = require('../internals/get-built-in');
6var NativePromise = require('../internals/native-promise-constructor');
7var redefine = require('../internals/redefine');
8var redefineAll = require('../internals/redefine-all');
9var setToStringTag = require('../internals/set-to-string-tag');
10var setSpecies = require('../internals/set-species');
11var isObject = require('../internals/is-object');
12var aFunction = require('../internals/a-function');
13var anInstance = require('../internals/an-instance');
14var classof = require('../internals/classof-raw');
15var iterate = require('../internals/iterate');
16var checkCorrectnessOfIteration = require('../internals/check-correctness-of-iteration');
17var speciesConstructor = require('../internals/species-constructor');
18var task = require('../internals/task').set;
19var microtask = require('../internals/microtask');
20var promiseResolve = require('../internals/promise-resolve');
21var hostReportErrors = require('../internals/host-report-errors');
22var newPromiseCapabilityModule = require('../internals/new-promise-capability');
23var perform = require('../internals/perform');
24var InternalStateModule = require('../internals/internal-state');
25var isForced = require('../internals/is-forced');
26var wellKnownSymbol = require('../internals/well-known-symbol');
27var V8_VERSION = require('../internals/v8-version');
28
29var SPECIES = wellKnownSymbol('species');
30var PROMISE = 'Promise';
31var getInternalState = InternalStateModule.get;
32var setInternalState = InternalStateModule.set;
33var getInternalPromiseState = InternalStateModule.getterFor(PROMISE);
34var PromiseConstructor = NativePromise;
35var TypeError = global.TypeError;
36var document = global.document;
37var process = global.process;
38var $fetch = getBuiltIn('fetch');
39var newPromiseCapability = newPromiseCapabilityModule.f;
40var newGenericPromiseCapability = newPromiseCapability;
41var IS_NODE = classof(process) == 'process';
42var DISPATCH_EVENT = !!(document && document.createEvent && global.dispatchEvent);
43var UNHANDLED_REJECTION = 'unhandledrejection';
44var REJECTION_HANDLED = 'rejectionhandled';
45var PENDING = 0;
46var FULFILLED = 1;
47var REJECTED = 2;
48var HANDLED = 1;
49var UNHANDLED = 2;
50var Internal, OwnPromiseCapability, PromiseWrapper, nativeThen;
51
52var FORCED = isForced(PROMISE, function () {
53 // correct subclassing with @@species support
54 var promise = PromiseConstructor.resolve(1);
55 var empty = function () { /* empty */ };
56 var FakePromise = (promise.constructor = {})[SPECIES] = function (exec) {
57 exec(empty, empty);
58 };
59 // unhandled rejections tracking support, NodeJS Promise without it fails @@species test
60 return !((IS_NODE || typeof PromiseRejectionEvent == 'function')
61 && (!IS_PURE || promise['finally'])
62 && promise.then(empty) instanceof FakePromise
63 // v8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
64 // https://bugs.chromium.org/p/chromium/issues/detail?id=830565
65 // we can't detect it synchronously, so just check versions
66 && V8_VERSION !== 66);
67});
68
69var INCORRECT_ITERATION = FORCED || !checkCorrectnessOfIteration(function (iterable) {
70 PromiseConstructor.all(iterable)['catch'](function () { /* empty */ });
71});
72
73// helpers
74var isThenable = function (it) {
75 var then;
76 return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
77};
78
79var notify = function (promise, state, isReject) {
80 if (state.notified) return;
81 state.notified = true;
82 var chain = state.reactions;
83 microtask(function () {
84 var value = state.value;
85 var ok = state.state == FULFILLED;
86 var index = 0;
87 // variable length - can't use forEach
88 while (chain.length > index) {
89 var reaction = chain[index++];
90 var handler = ok ? reaction.ok : reaction.fail;
91 var resolve = reaction.resolve;
92 var reject = reaction.reject;
93 var domain = reaction.domain;
94 var result, then, exited;
95 try {
96 if (handler) {
97 if (!ok) {
98 if (state.rejection === UNHANDLED) onHandleUnhandled(promise, state);
99 state.rejection = HANDLED;
100 }
101 if (handler === true) result = value;
102 else {
103 if (domain) domain.enter();
104 result = handler(value); // can throw
105 if (domain) {
106 domain.exit();
107 exited = true;
108 }
109 }
110 if (result === reaction.promise) {
111 reject(TypeError('Promise-chain cycle'));
112 } else if (then = isThenable(result)) {
113 then.call(result, resolve, reject);
114 } else resolve(result);
115 } else reject(value);
116 } catch (error) {
117 if (domain && !exited) domain.exit();
118 reject(error);
119 }
120 }
121 state.reactions = [];
122 state.notified = false;
123 if (isReject && !state.rejection) onUnhandled(promise, state);
124 });
125};
126
127var dispatchEvent = function (name, promise, reason) {
128 var event, handler;
129 if (DISPATCH_EVENT) {
130 event = document.createEvent('Event');
131 event.promise = promise;
132 event.reason = reason;
133 event.initEvent(name, false, true);
134 global.dispatchEvent(event);
135 } else event = { promise: promise, reason: reason };
136 if (handler = global['on' + name]) handler(event);
137 else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
138};
139
140var onUnhandled = function (promise, state) {
141 task.call(global, function () {
142 var value = state.value;
143 var IS_UNHANDLED = isUnhandled(state);
144 var result;
145 if (IS_UNHANDLED) {
146 result = perform(function () {
147 if (IS_NODE) {
148 process.emit('unhandledRejection', value, promise);
149 } else dispatchEvent(UNHANDLED_REJECTION, promise, value);
150 });
151 // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
152 state.rejection = IS_NODE || isUnhandled(state) ? UNHANDLED : HANDLED;
153 if (result.error) throw result.value;
154 }
155 });
156};
157
158var isUnhandled = function (state) {
159 return state.rejection !== HANDLED && !state.parent;
160};
161
162var onHandleUnhandled = function (promise, state) {
163 task.call(global, function () {
164 if (IS_NODE) {
165 process.emit('rejectionHandled', promise);
166 } else dispatchEvent(REJECTION_HANDLED, promise, state.value);
167 });
168};
169
170var bind = function (fn, promise, state, unwrap) {
171 return function (value) {
172 fn(promise, state, value, unwrap);
173 };
174};
175
176var internalReject = function (promise, state, value, unwrap) {
177 if (state.done) return;
178 state.done = true;
179 if (unwrap) state = unwrap;
180 state.value = value;
181 state.state = REJECTED;
182 notify(promise, state, true);
183};
184
185var internalResolve = function (promise, state, value, unwrap) {
186 if (state.done) return;
187 state.done = true;
188 if (unwrap) state = unwrap;
189 try {
190 if (promise === value) throw TypeError("Promise can't be resolved itself");
191 var then = isThenable(value);
192 if (then) {
193 microtask(function () {
194 var wrapper = { done: false };
195 try {
196 then.call(value,
197 bind(internalResolve, promise, wrapper, state),
198 bind(internalReject, promise, wrapper, state)
199 );
200 } catch (error) {
201 internalReject(promise, wrapper, error, state);
202 }
203 });
204 } else {
205 state.value = value;
206 state.state = FULFILLED;
207 notify(promise, state, false);
208 }
209 } catch (error) {
210 internalReject(promise, { done: false }, error, state);
211 }
212};
213
214// constructor polyfill
215if (FORCED) {
216 // 25.4.3.1 Promise(executor)
217 PromiseConstructor = function Promise(executor) {
218 anInstance(this, PromiseConstructor, PROMISE);
219 aFunction(executor);
220 Internal.call(this);
221 var state = getInternalState(this);
222 try {
223 executor(bind(internalResolve, this, state), bind(internalReject, this, state));
224 } catch (error) {
225 internalReject(this, state, error);
226 }
227 };
228 // eslint-disable-next-line no-unused-vars
229 Internal = function Promise(executor) {
230 setInternalState(this, {
231 type: PROMISE,
232 done: false,
233 notified: false,
234 parent: false,
235 reactions: [],
236 rejection: false,
237 state: PENDING,
238 value: undefined
239 });
240 };
241 Internal.prototype = redefineAll(PromiseConstructor.prototype, {
242 // `Promise.prototype.then` method
243 // https://tc39.github.io/ecma262/#sec-promise.prototype.then
244 then: function then(onFulfilled, onRejected) {
245 var state = getInternalPromiseState(this);
246 var reaction = newPromiseCapability(speciesConstructor(this, PromiseConstructor));
247 reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
248 reaction.fail = typeof onRejected == 'function' && onRejected;
249 reaction.domain = IS_NODE ? process.domain : undefined;
250 state.parent = true;
251 state.reactions.push(reaction);
252 if (state.state != PENDING) notify(this, state, false);
253 return reaction.promise;
254 },
255 // `Promise.prototype.catch` method
256 // https://tc39.github.io/ecma262/#sec-promise.prototype.catch
257 'catch': function (onRejected) {
258 return this.then(undefined, onRejected);
259 }
260 });
261 OwnPromiseCapability = function () {
262 var promise = new Internal();
263 var state = getInternalState(promise);
264 this.promise = promise;
265 this.resolve = bind(internalResolve, promise, state);
266 this.reject = bind(internalReject, promise, state);
267 };
268 newPromiseCapabilityModule.f = newPromiseCapability = function (C) {
269 return C === PromiseConstructor || C === PromiseWrapper
270 ? new OwnPromiseCapability(C)
271 : newGenericPromiseCapability(C);
272 };
273
274 if (!IS_PURE && typeof NativePromise == 'function') {
275 nativeThen = NativePromise.prototype.then;
276
277 // wrap native Promise#then for native async functions
278 redefine(NativePromise.prototype, 'then', function then(onFulfilled, onRejected) {
279 var that = this;
280 return new PromiseConstructor(function (resolve, reject) {
281 nativeThen.call(that, resolve, reject);
282 }).then(onFulfilled, onRejected);
283 // https://github.com/zloirock/core-js/issues/640
284 }, { unsafe: true });
285
286 // wrap fetch result
287 if (typeof $fetch == 'function') $({ global: true, enumerable: true, forced: true }, {
288 // eslint-disable-next-line no-unused-vars
289 fetch: function fetch(input /* , init */) {
290 return promiseResolve(PromiseConstructor, $fetch.apply(global, arguments));
291 }
292 });
293 }
294}
295
296$({ global: true, wrap: true, forced: FORCED }, {
297 Promise: PromiseConstructor
298});
299
300setToStringTag(PromiseConstructor, PROMISE, false, true);
301setSpecies(PROMISE);
302
303PromiseWrapper = getBuiltIn(PROMISE);
304
305// statics
306$({ target: PROMISE, stat: true, forced: FORCED }, {
307 // `Promise.reject` method
308 // https://tc39.github.io/ecma262/#sec-promise.reject
309 reject: function reject(r) {
310 var capability = newPromiseCapability(this);
311 capability.reject.call(undefined, r);
312 return capability.promise;
313 }
314});
315
316$({ target: PROMISE, stat: true, forced: IS_PURE || FORCED }, {
317 // `Promise.resolve` method
318 // https://tc39.github.io/ecma262/#sec-promise.resolve
319 resolve: function resolve(x) {
320 return promiseResolve(IS_PURE && this === PromiseWrapper ? PromiseConstructor : this, x);
321 }
322});
323
324$({ target: PROMISE, stat: true, forced: INCORRECT_ITERATION }, {
325 // `Promise.all` method
326 // https://tc39.github.io/ecma262/#sec-promise.all
327 all: function all(iterable) {
328 var C = this;
329 var capability = newPromiseCapability(C);
330 var resolve = capability.resolve;
331 var reject = capability.reject;
332 var result = perform(function () {
333 var $promiseResolve = aFunction(C.resolve);
334 var values = [];
335 var counter = 0;
336 var remaining = 1;
337 iterate(iterable, function (promise) {
338 var index = counter++;
339 var alreadyCalled = false;
340 values.push(undefined);
341 remaining++;
342 $promiseResolve.call(C, promise).then(function (value) {
343 if (alreadyCalled) return;
344 alreadyCalled = true;
345 values[index] = value;
346 --remaining || resolve(values);
347 }, reject);
348 });
349 --remaining || resolve(values);
350 });
351 if (result.error) reject(result.value);
352 return capability.promise;
353 },
354 // `Promise.race` method
355 // https://tc39.github.io/ecma262/#sec-promise.race
356 race: function race(iterable) {
357 var C = this;
358 var capability = newPromiseCapability(C);
359 var reject = capability.reject;
360 var result = perform(function () {
361 var $promiseResolve = aFunction(C.resolve);
362 iterate(iterable, function (promise) {
363 $promiseResolve.call(C, promise).then(capability.resolve, reject);
364 });
365 });
366 if (result.error) reject(result.value);
367 return capability.promise;
368 }
369});