2019-09-25 13:30:05 +05:30
|
|
|
'use strict';
|
|
|
|
var $ = require('../internals/export');
|
|
|
|
var IS_PURE = require('../internals/is-pure');
|
|
|
|
var global = require('../internals/global');
|
2019-10-31 01:37:42 +05:30
|
|
|
var getBuiltIn = require('../internals/get-built-in');
|
2019-09-25 13:30:05 +05:30
|
|
|
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');
|
2019-12-04 20:38:33 +05:30
|
|
|
var inspectSource = require('../internals/inspect-source');
|
2019-09-25 13:30:05 +05:30
|
|
|
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');
|
2019-10-31 01:37:42 +05:30
|
|
|
var V8_VERSION = require('../internals/v8-version');
|
2019-09-25 13:30:05 +05:30
|
|
|
|
|
|
|
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;
|
2019-10-31 01:37:42 +05:30
|
|
|
var $fetch = getBuiltIn('fetch');
|
2019-09-25 13:30:05 +05:30
|
|
|
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 () {
|
2019-12-04 20:38:33 +05:30
|
|
|
var GLOBAL_CORE_JS_PROMISE = inspectSource(PromiseConstructor) !== String(PromiseConstructor);
|
|
|
|
if (!GLOBAL_CORE_JS_PROMISE) {
|
|
|
|
// 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 (V8_VERSION === 66) return true;
|
|
|
|
// Unhandled rejections tracking support, NodeJS Promise without it fails @@species test
|
|
|
|
if (!IS_NODE && typeof PromiseRejectionEvent != 'function') return true;
|
|
|
|
}
|
2019-10-31 01:37:42 +05:30
|
|
|
// We need Promise#finally in the pure version for preventing prototype pollution
|
|
|
|
if (IS_PURE && !PromiseConstructor.prototype['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(PromiseConstructor)) return false;
|
|
|
|
// Detect correctness of subclassing with @@species support
|
2019-09-25 13:30:05 +05:30
|
|
|
var promise = PromiseConstructor.resolve(1);
|
2019-10-31 01:37:42 +05:30
|
|
|
var FakePromise = function (exec) {
|
|
|
|
exec(function () { /* empty */ }, function () { /* empty */ });
|
2019-09-25 13:30:05 +05:30
|
|
|
};
|
2019-10-31 01:37:42 +05:30
|
|
|
var constructor = promise.constructor = {};
|
|
|
|
constructor[SPECIES] = FakePromise;
|
|
|
|
return !(promise.then(function () { /* empty */ }) instanceof FakePromise);
|
2019-09-25 13:30:05 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
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);
|
2019-10-31 01:37:42 +05:30
|
|
|
// https://github.com/zloirock/core-js/issues/640
|
|
|
|
}, { unsafe: true });
|
2019-09-25 13:30:05 +05:30
|
|
|
|
|
|
|
// wrap fetch result
|
|
|
|
if (typeof $fetch == 'function') $({ global: true, enumerable: true, forced: true }, {
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
2019-10-31 01:37:42 +05:30
|
|
|
fetch: function fetch(input /* , init */) {
|
2019-09-25 13:30:05 +05:30
|
|
|
return promiseResolve(PromiseConstructor, $fetch.apply(global, arguments));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$({ global: true, wrap: true, forced: FORCED }, {
|
|
|
|
Promise: PromiseConstructor
|
|
|
|
});
|
|
|
|
|
|
|
|
setToStringTag(PromiseConstructor, PROMISE, false, true);
|
|
|
|
setSpecies(PROMISE);
|
|
|
|
|
2019-10-31 01:37:42 +05:30
|
|
|
PromiseWrapper = getBuiltIn(PROMISE);
|
2019-09-25 13:30:05 +05:30
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
});
|