| '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 setToStringTag = require('../internals/set-to-string-tag'); |
| var setSpecies = require('../internals/set-species'); |
| var isObject = require('../internals/is-object'); |
| var aFunction = require('../internals/a-function'); |
| var anInstance = require('../internals/an-instance'); |
| var classof = require('../internals/classof-raw'); |
| 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 V8_VERSION = require('../internals/v8-version'); |
| |
| var SPECIES = wellKnownSymbol('species'); |
| var PROMISE = 'Promise'; |
| var getInternalState = InternalStateModule.get; |
| var setInternalState = InternalStateModule.set; |
| var getInternalPromiseState = InternalStateModule.getterFor(PROMISE); |
| var PromiseConstructor = NativePromise; |
| var TypeError = global.TypeError; |
| var document = global.document; |
| var process = global.process; |
| var $fetch = getBuiltIn('fetch'); |
| var newPromiseCapability = newPromiseCapabilityModule.f; |
| var newGenericPromiseCapability = newPromiseCapability; |
| var IS_NODE = classof(process) == 'process'; |
| var DISPATCH_EVENT = !!(document && document.createEvent && global.dispatchEvent); |
| var UNHANDLED_REJECTION = 'unhandledrejection'; |
| var REJECTION_HANDLED = 'rejectionhandled'; |
| var PENDING = 0; |
| var FULFILLED = 1; |
| var REJECTED = 2; |
| var HANDLED = 1; |
| var UNHANDLED = 2; |
| var Internal, OwnPromiseCapability, PromiseWrapper, nativeThen; |
| |
| var FORCED = isForced(PROMISE, function () { |
| // correct subclassing with @@species support |
| var promise = PromiseConstructor.resolve(1); |
| var empty = function () { /* empty */ }; |
| var FakePromise = (promise.constructor = {})[SPECIES] = function (exec) { |
| exec(empty, empty); |
| }; |
| // unhandled rejections tracking support, NodeJS Promise without it fails @@species test |
| return !((IS_NODE || typeof PromiseRejectionEvent == 'function') |
| && (!IS_PURE || promise['finally']) |
| && promise.then(empty) instanceof FakePromise |
| // 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 |
| && V8_VERSION !== 66); |
| }); |
| |
| var INCORRECT_ITERATION = FORCED || !checkCorrectnessOfIteration(function (iterable) { |
| PromiseConstructor.all(iterable)['catch'](function () { /* empty */ }); |
| }); |
| |
| // helpers |
| var isThenable = function (it) { |
| var then; |
| return isObject(it) && typeof (then = it.then) == 'function' ? then : false; |
| }; |
| |
| var notify = function (promise, 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(promise, 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(promise, 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 (handler = global['on' + name]) handler(event); |
| else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason); |
| }; |
| |
| var onUnhandled = function (promise, state) { |
| task.call(global, function () { |
| 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 (promise, state) { |
| task.call(global, function () { |
| if (IS_NODE) { |
| process.emit('rejectionHandled', promise); |
| } else dispatchEvent(REJECTION_HANDLED, promise, state.value); |
| }); |
| }; |
| |
| var bind = function (fn, promise, state, unwrap) { |
| return function (value) { |
| fn(promise, state, value, unwrap); |
| }; |
| }; |
| |
| var internalReject = function (promise, state, value, unwrap) { |
| if (state.done) return; |
| state.done = true; |
| if (unwrap) state = unwrap; |
| state.value = value; |
| state.state = REJECTED; |
| notify(promise, state, true); |
| }; |
| |
| var internalResolve = function (promise, state, value, unwrap) { |
| if (state.done) return; |
| state.done = true; |
| if (unwrap) state = unwrap; |
| try { |
| if (promise === 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, promise, wrapper, state), |
| bind(internalReject, promise, wrapper, state) |
| ); |
| } catch (error) { |
| internalReject(promise, wrapper, error, state); |
| } |
| }); |
| } else { |
| state.value = value; |
| state.state = FULFILLED; |
| notify(promise, state, false); |
| } |
| } catch (error) { |
| internalReject(promise, { done: false }, error, state); |
| } |
| }; |
| |
| // constructor polyfill |
| if (FORCED) { |
| // 25.4.3.1 Promise(executor) |
| PromiseConstructor = function Promise(executor) { |
| anInstance(this, PromiseConstructor, PROMISE); |
| aFunction(executor); |
| Internal.call(this); |
| var state = getInternalState(this); |
| try { |
| executor(bind(internalResolve, this, state), bind(internalReject, this, state)); |
| } catch (error) { |
| internalReject(this, state, error); |
| } |
| }; |
| // eslint-disable-next-line no-unused-vars |
| Internal = function Promise(executor) { |
| setInternalState(this, { |
| type: PROMISE, |
| done: false, |
| notified: false, |
| parent: false, |
| reactions: [], |
| rejection: false, |
| state: PENDING, |
| value: undefined |
| }); |
| }; |
| Internal.prototype = redefineAll(PromiseConstructor.prototype, { |
| // `Promise.prototype.then` method |
| // https://tc39.github.io/ecma262/#sec-promise.prototype.then |
| then: function then(onFulfilled, onRejected) { |
| var state = getInternalPromiseState(this); |
| var reaction = newPromiseCapability(speciesConstructor(this, PromiseConstructor)); |
| reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true; |
| reaction.fail = typeof onRejected == 'function' && onRejected; |
| reaction.domain = IS_NODE ? process.domain : undefined; |
| state.parent = true; |
| state.reactions.push(reaction); |
| if (state.state != PENDING) notify(this, state, false); |
| return reaction.promise; |
| }, |
| // `Promise.prototype.catch` method |
| // https://tc39.github.io/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, promise, state); |
| this.reject = bind(internalReject, promise, state); |
| }; |
| newPromiseCapabilityModule.f = newPromiseCapability = function (C) { |
| return C === PromiseConstructor || C === PromiseWrapper |
| ? new OwnPromiseCapability(C) |
| : newGenericPromiseCapability(C); |
| }; |
| |
| if (!IS_PURE && typeof NativePromise == 'function') { |
| nativeThen = NativePromise.prototype.then; |
| |
| // wrap native Promise#then for native async functions |
| redefine(NativePromise.prototype, '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 }); |
| |
| // wrap fetch result |
| if (typeof $fetch == 'function') $({ global: true, enumerable: true, forced: true }, { |
| // eslint-disable-next-line no-unused-vars |
| fetch: function fetch(input /* , init */) { |
| return promiseResolve(PromiseConstructor, $fetch.apply(global, arguments)); |
| } |
| }); |
| } |
| } |
| |
| $({ 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.github.io/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.github.io/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.github.io/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 = aFunction(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.github.io/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 = aFunction(C.resolve); |
| iterate(iterable, function (promise) { |
| $promiseResolve.call(C, promise).then(capability.resolve, reject); |
| }); |
| }); |
| if (result.error) reject(result.value); |
| return capability.promise; |
| } |
| }); |