| | |
| | | 'use strict'; |
| | | var $ = require('../internals/export'); |
| | | var IS_PURE = require('../internals/is-pure'); |
| | | var global = require('../internals/global'); |
| | | var getBuiltIn = require('../internals/get-built-in'); |
| | | var NativePromise = require('../internals/native-promise-constructor'); |
| | | var redefine = require('../internals/redefine'); |
| | | var redefineAll = require('../internals/redefine-all'); |
| | | var setPrototypeOf = require('../internals/object-set-prototype-of'); |
| | | var setToStringTag = require('../internals/set-to-string-tag'); |
| | | var setSpecies = require('../internals/set-species'); |
| | | var aCallable = require('../internals/a-callable'); |
| | | var isCallable = require('../internals/is-callable'); |
| | | var isObject = require('../internals/is-object'); |
| | | var anInstance = require('../internals/an-instance'); |
| | | var inspectSource = require('../internals/inspect-source'); |
| | | var iterate = require('../internals/iterate'); |
| | | var checkCorrectnessOfIteration = require('../internals/check-correctness-of-iteration'); |
| | | var speciesConstructor = require('../internals/species-constructor'); |
| | | var task = require('../internals/task').set; |
| | | var microtask = require('../internals/microtask'); |
| | | var promiseResolve = require('../internals/promise-resolve'); |
| | | var hostReportErrors = require('../internals/host-report-errors'); |
| | | var newPromiseCapabilityModule = require('../internals/new-promise-capability'); |
| | | var perform = require('../internals/perform'); |
| | | var InternalStateModule = require('../internals/internal-state'); |
| | | var isForced = require('../internals/is-forced'); |
| | | var wellKnownSymbol = require('../internals/well-known-symbol'); |
| | | var IS_BROWSER = require('../internals/engine-is-browser'); |
| | | var IS_NODE = require('../internals/engine-is-node'); |
| | | var V8_VERSION = require('../internals/engine-v8-version'); |
| | | |
| | | var SPECIES = wellKnownSymbol('species'); |
| | | var PROMISE = 'Promise'; |
| | | var getInternalState = InternalStateModule.get; |
| | | var setInternalState = InternalStateModule.set; |
| | | var getInternalPromiseState = InternalStateModule.getterFor(PROMISE); |
| | | var NativePromisePrototype = NativePromise && NativePromise.prototype; |
| | | var PromiseConstructor = NativePromise; |
| | | var PromiseConstructorPrototype = NativePromisePrototype; |
| | | var TypeError = global.TypeError; |
| | | var document = global.document; |
| | | var process = global.process; |
| | | var newPromiseCapability = newPromiseCapabilityModule.f; |
| | | var newGenericPromiseCapability = newPromiseCapability; |
| | | var DISPATCH_EVENT = !!(document && document.createEvent && global.dispatchEvent); |
| | | var NATIVE_REJECTION_EVENT = isCallable(global.PromiseRejectionEvent); |
| | | var UNHANDLED_REJECTION = 'unhandledrejection'; |
| | | var REJECTION_HANDLED = 'rejectionhandled'; |
| | | var PENDING = 0; |
| | | var FULFILLED = 1; |
| | | var REJECTED = 2; |
| | | var HANDLED = 1; |
| | | var UNHANDLED = 2; |
| | | var SUBCLASSING = false; |
| | | var Internal, OwnPromiseCapability, PromiseWrapper, nativeThen; |
| | | |
| | | var FORCED = isForced(PROMISE, function () { |
| | | var PROMISE_CONSTRUCTOR_SOURCE = inspectSource(PromiseConstructor); |
| | | var GLOBAL_CORE_JS_PROMISE = PROMISE_CONSTRUCTOR_SOURCE !== String(PromiseConstructor); |
| | | // V8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables |
| | | // https://bugs.chromium.org/p/chromium/issues/detail?id=830565 |
| | | // We can't detect it synchronously, so just check versions |
| | | if (!GLOBAL_CORE_JS_PROMISE && V8_VERSION === 66) return true; |
| | | // We need Promise#finally in the pure version for preventing prototype pollution |
| | | if (IS_PURE && !PromiseConstructorPrototype['finally']) return true; |
| | | // We can't use @@species feature detection in V8 since it causes |
| | | // deoptimization and performance degradation |
| | | // https://github.com/zloirock/core-js/issues/679 |
| | | if (V8_VERSION >= 51 && /native code/.test(PROMISE_CONSTRUCTOR_SOURCE)) return false; |
| | | // Detect correctness of subclassing with @@species support |
| | | var promise = new PromiseConstructor(function (resolve) { resolve(1); }); |
| | | var FakePromise = function (exec) { |
| | | exec(function () { /* empty */ }, function () { /* empty */ }); |
| | | }; |
| | | var constructor = promise.constructor = {}; |
| | | constructor[SPECIES] = FakePromise; |
| | | SUBCLASSING = promise.then(function () { /* empty */ }) instanceof FakePromise; |
| | | if (!SUBCLASSING) return true; |
| | | // Unhandled rejections tracking support, NodeJS Promise without it fails @@species test |
| | | return !GLOBAL_CORE_JS_PROMISE && IS_BROWSER && !NATIVE_REJECTION_EVENT; |
| | | }); |
| | | |
| | | var INCORRECT_ITERATION = FORCED || !checkCorrectnessOfIteration(function (iterable) { |
| | | PromiseConstructor.all(iterable)['catch'](function () { /* empty */ }); |
| | | }); |
| | | |
| | | // helpers |
| | | var isThenable = function (it) { |
| | | var then; |
| | | return isObject(it) && isCallable(then = it.then) ? then : false; |
| | | }; |
| | | |
| | | var notify = function (state, isReject) { |
| | | if (state.notified) return; |
| | | state.notified = true; |
| | | var chain = state.reactions; |
| | | microtask(function () { |
| | | var value = state.value; |
| | | var ok = state.state == FULFILLED; |
| | | var index = 0; |
| | | // variable length - can't use forEach |
| | | while (chain.length > index) { |
| | | var reaction = chain[index++]; |
| | | var handler = ok ? reaction.ok : reaction.fail; |
| | | var resolve = reaction.resolve; |
| | | var reject = reaction.reject; |
| | | var domain = reaction.domain; |
| | | var result, then, exited; |
| | | try { |
| | | if (handler) { |
| | | if (!ok) { |
| | | if (state.rejection === UNHANDLED) onHandleUnhandled(state); |
| | | state.rejection = HANDLED; |
| | | } |
| | | if (handler === true) result = value; |
| | | else { |
| | | if (domain) domain.enter(); |
| | | result = handler(value); // can throw |
| | | if (domain) { |
| | | domain.exit(); |
| | | exited = true; |
| | | } |
| | | } |
| | | if (result === reaction.promise) { |
| | | reject(TypeError('Promise-chain cycle')); |
| | | } else if (then = isThenable(result)) { |
| | | then.call(result, resolve, reject); |
| | | } else resolve(result); |
| | | } else reject(value); |
| | | } catch (error) { |
| | | if (domain && !exited) domain.exit(); |
| | | reject(error); |
| | | } |
| | | } |
| | | state.reactions = []; |
| | | state.notified = false; |
| | | if (isReject && !state.rejection) onUnhandled(state); |
| | | }); |
| | | }; |
| | | |
| | | var dispatchEvent = function (name, promise, reason) { |
| | | var event, handler; |
| | | if (DISPATCH_EVENT) { |
| | | event = document.createEvent('Event'); |
| | | event.promise = promise; |
| | | event.reason = reason; |
| | | event.initEvent(name, false, true); |
| | | global.dispatchEvent(event); |
| | | } else event = { promise: promise, reason: reason }; |
| | | if (!NATIVE_REJECTION_EVENT && (handler = global['on' + name])) handler(event); |
| | | else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason); |
| | | }; |
| | | |
| | | var onUnhandled = function (state) { |
| | | task.call(global, function () { |
| | | var promise = state.facade; |
| | | var value = state.value; |
| | | var IS_UNHANDLED = isUnhandled(state); |
| | | var result; |
| | | if (IS_UNHANDLED) { |
| | | result = perform(function () { |
| | | if (IS_NODE) { |
| | | process.emit('unhandledRejection', value, promise); |
| | | } else dispatchEvent(UNHANDLED_REJECTION, promise, value); |
| | | }); |
| | | // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should |
| | | state.rejection = IS_NODE || isUnhandled(state) ? UNHANDLED : HANDLED; |
| | | if (result.error) throw result.value; |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | var isUnhandled = function (state) { |
| | | return state.rejection !== HANDLED && !state.parent; |
| | | }; |
| | | |
| | | var onHandleUnhandled = function (state) { |
| | | task.call(global, function () { |
| | | var promise = state.facade; |
| | | if (IS_NODE) { |
| | | process.emit('rejectionHandled', promise); |
| | | } else dispatchEvent(REJECTION_HANDLED, promise, state.value); |
| | | }); |
| | | }; |
| | | |
| | | var bind = function (fn, state, unwrap) { |
| | | return function (value) { |
| | | fn(state, value, unwrap); |
| | | }; |
| | | }; |
| | | |
| | | var internalReject = function (state, value, unwrap) { |
| | | if (state.done) return; |
| | | state.done = true; |
| | | if (unwrap) state = unwrap; |
| | | state.value = value; |
| | | state.state = REJECTED; |
| | | notify(state, true); |
| | | }; |
| | | |
| | | var internalResolve = function (state, value, unwrap) { |
| | | if (state.done) return; |
| | | state.done = true; |
| | | if (unwrap) state = unwrap; |
| | | try { |
| | | if (state.facade === value) throw TypeError("Promise can't be resolved itself"); |
| | | var then = isThenable(value); |
| | | if (then) { |
| | | microtask(function () { |
| | | var wrapper = { done: false }; |
| | | try { |
| | | then.call(value, |
| | | bind(internalResolve, wrapper, state), |
| | | bind(internalReject, wrapper, state) |
| | | ); |
| | | } catch (error) { |
| | | internalReject(wrapper, error, state); |
| | | } |
| | | }); |
| | | } else { |
| | | state.value = value; |
| | | state.state = FULFILLED; |
| | | notify(state, false); |
| | | } |
| | | } catch (error) { |
| | | internalReject({ done: false }, error, state); |
| | | } |
| | | }; |
| | | |
| | | // constructor polyfill |
| | | if (FORCED) { |
| | | // 25.4.3.1 Promise(executor) |
| | | PromiseConstructor = function Promise(executor) { |
| | | anInstance(this, PromiseConstructor, PROMISE); |
| | | aCallable(executor); |
| | | Internal.call(this); |
| | | var state = getInternalState(this); |
| | | try { |
| | | executor(bind(internalResolve, state), bind(internalReject, state)); |
| | | } catch (error) { |
| | | internalReject(state, error); |
| | | } |
| | | }; |
| | | PromiseConstructorPrototype = PromiseConstructor.prototype; |
| | | // eslint-disable-next-line no-unused-vars -- required for `.length` |
| | | Internal = function Promise(executor) { |
| | | setInternalState(this, { |
| | | type: PROMISE, |
| | | done: false, |
| | | notified: false, |
| | | parent: false, |
| | | reactions: [], |
| | | rejection: false, |
| | | state: PENDING, |
| | | value: undefined |
| | | }); |
| | | }; |
| | | Internal.prototype = redefineAll(PromiseConstructorPrototype, { |
| | | // `Promise.prototype.then` method |
| | | // https://tc39.es/ecma262/#sec-promise.prototype.then |
| | | then: function then(onFulfilled, onRejected) { |
| | | var state = getInternalPromiseState(this); |
| | | var reaction = newPromiseCapability(speciesConstructor(this, PromiseConstructor)); |
| | | reaction.ok = isCallable(onFulfilled) ? onFulfilled : true; |
| | | reaction.fail = isCallable(onRejected) && onRejected; |
| | | reaction.domain = IS_NODE ? process.domain : undefined; |
| | | state.parent = true; |
| | | state.reactions.push(reaction); |
| | | if (state.state != PENDING) notify(state, false); |
| | | return reaction.promise; |
| | | }, |
| | | // `Promise.prototype.catch` method |
| | | // https://tc39.es/ecma262/#sec-promise.prototype.catch |
| | | 'catch': function (onRejected) { |
| | | return this.then(undefined, onRejected); |
| | | } |
| | | }); |
| | | OwnPromiseCapability = function () { |
| | | var promise = new Internal(); |
| | | var state = getInternalState(promise); |
| | | this.promise = promise; |
| | | this.resolve = bind(internalResolve, state); |
| | | this.reject = bind(internalReject, state); |
| | | }; |
| | | newPromiseCapabilityModule.f = newPromiseCapability = function (C) { |
| | | return C === PromiseConstructor || C === PromiseWrapper |
| | | ? new OwnPromiseCapability(C) |
| | | : newGenericPromiseCapability(C); |
| | | }; |
| | | |
| | | if (!IS_PURE && isCallable(NativePromise) && NativePromisePrototype !== Object.prototype) { |
| | | nativeThen = NativePromisePrototype.then; |
| | | |
| | | if (!SUBCLASSING) { |
| | | // make `Promise#then` return a polyfilled `Promise` for native promise-based APIs |
| | | redefine(NativePromisePrototype, 'then', function then(onFulfilled, onRejected) { |
| | | var that = this; |
| | | return new PromiseConstructor(function (resolve, reject) { |
| | | nativeThen.call(that, resolve, reject); |
| | | }).then(onFulfilled, onRejected); |
| | | // https://github.com/zloirock/core-js/issues/640 |
| | | }, { unsafe: true }); |
| | | |
| | | // makes sure that native promise-based APIs `Promise#catch` properly works with patched `Promise#then` |
| | | redefine(NativePromisePrototype, 'catch', PromiseConstructorPrototype['catch'], { unsafe: true }); |
| | | } |
| | | |
| | | // make `.constructor === Promise` work for native promise-based APIs |
| | | try { |
| | | delete NativePromisePrototype.constructor; |
| | | } catch (error) { /* empty */ } |
| | | |
| | | // make `instanceof Promise` work for native promise-based APIs |
| | | if (setPrototypeOf) { |
| | | setPrototypeOf(NativePromisePrototype, PromiseConstructorPrototype); |
| | | } |
| | | } |
| | | } |
| | | |
| | | $({ global: true, wrap: true, forced: FORCED }, { |
| | | Promise: PromiseConstructor |
| | | }); |
| | | |
| | | setToStringTag(PromiseConstructor, PROMISE, false, true); |
| | | setSpecies(PROMISE); |
| | | |
| | | PromiseWrapper = getBuiltIn(PROMISE); |
| | | |
| | | // statics |
| | | $({ target: PROMISE, stat: true, forced: FORCED }, { |
| | | // `Promise.reject` method |
| | | // https://tc39.es/ecma262/#sec-promise.reject |
| | | reject: function reject(r) { |
| | | var capability = newPromiseCapability(this); |
| | | capability.reject.call(undefined, r); |
| | | return capability.promise; |
| | | } |
| | | }); |
| | | |
| | | $({ target: PROMISE, stat: true, forced: IS_PURE || FORCED }, { |
| | | // `Promise.resolve` method |
| | | // https://tc39.es/ecma262/#sec-promise.resolve |
| | | resolve: function resolve(x) { |
| | | return promiseResolve(IS_PURE && this === PromiseWrapper ? PromiseConstructor : this, x); |
| | | } |
| | | }); |
| | | |
| | | $({ target: PROMISE, stat: true, forced: INCORRECT_ITERATION }, { |
| | | // `Promise.all` method |
| | | // https://tc39.es/ecma262/#sec-promise.all |
| | | all: function all(iterable) { |
| | | var C = this; |
| | | var capability = newPromiseCapability(C); |
| | | var resolve = capability.resolve; |
| | | var reject = capability.reject; |
| | | var result = perform(function () { |
| | | var $promiseResolve = aCallable(C.resolve); |
| | | var values = []; |
| | | var counter = 0; |
| | | var remaining = 1; |
| | | iterate(iterable, function (promise) { |
| | | var index = counter++; |
| | | var alreadyCalled = false; |
| | | values.push(undefined); |
| | | remaining++; |
| | | $promiseResolve.call(C, promise).then(function (value) { |
| | | if (alreadyCalled) return; |
| | | alreadyCalled = true; |
| | | values[index] = value; |
| | | --remaining || resolve(values); |
| | | }, reject); |
| | | }); |
| | | --remaining || resolve(values); |
| | | }); |
| | | if (result.error) reject(result.value); |
| | | return capability.promise; |
| | | }, |
| | | // `Promise.race` method |
| | | // https://tc39.es/ecma262/#sec-promise.race |
| | | race: function race(iterable) { |
| | | var C = this; |
| | | var capability = newPromiseCapability(C); |
| | | var reject = capability.reject; |
| | | var result = perform(function () { |
| | | var $promiseResolve = aCallable(C.resolve); |
| | | iterate(iterable, function (promise) { |
| | | $promiseResolve.call(C, promise).then(capability.resolve, reject); |
| | | }); |
| | | }); |
| | | if (result.error) reject(result.value); |
| | | return capability.promise; |
| | | } |
| | | }); |
| | | // TODO: Remove this module from `core-js@4` since it's split to modules listed below |
| | | require('../modules/es.promise.constructor'); |
| | | require('../modules/es.promise.all'); |
| | | require('../modules/es.promise.catch'); |
| | | require('../modules/es.promise.race'); |
| | | require('../modules/es.promise.reject'); |
| | | require('../modules/es.promise.resolve'); |