Skip to content

Commit

Permalink
extract some internals from es.promise for make them shared in the …
Browse files Browse the repository at this point in the history
…future
  • Loading branch information
zloirock committed Feb 22, 2022
1 parent faa75c4 commit 1ebeeb2
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 57 deletions.
46 changes: 46 additions & 0 deletions packages/core-js/internals/promise-constructor-detection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
var global = require('../internals/global');
var NativePromiseConstructor = require('../internals/promise-native-constructor');
var isCallable = require('../internals/is-callable');
var isForced = require('../internals/is-forced');
var inspectSource = require('../internals/inspect-source');
var wellKnownSymbol = require('../internals/well-known-symbol');
var IS_BROWSER = require('../internals/engine-is-browser');
var IS_PURE = require('../internals/is-pure');
var V8_VERSION = require('../internals/engine-v8-version');

var NativePromisePrototype = NativePromiseConstructor && NativePromiseConstructor.prototype;
var SPECIES = wellKnownSymbol('species');
var SUBCLASSING = false;
var NATIVE_PROMISE_REJECTION_EVENT = isCallable(global.PromiseRejectionEvent);

var FORCED_PROMISE_CONSTRUCTOR = isForced('Promise', function () {
var PROMISE_CONSTRUCTOR_SOURCE = inspectSource(NativePromiseConstructor);
var GLOBAL_CORE_JS_PROMISE = PROMISE_CONSTRUCTOR_SOURCE !== String(NativePromiseConstructor);
// 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#{ catch, finally } in the pure version for preventing prototype pollution
if (IS_PURE && !(NativePromisePrototype['catch'] && NativePromisePrototype['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 NativePromiseConstructor(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_PROMISE_REJECTION_EVENT;
});

module.exports = {
CONSTRUCTOR: FORCED_PROMISE_CONSTRUCTOR,
REJECTION_EVENT: NATIVE_PROMISE_REJECTION_EVENT,
SUBCLASSING: SUBCLASSING
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
var NativePromiseConstructor = require('../internals/promise-native-constructor');
var checkCorrectnessOfIteration = require('../internals/check-correctness-of-iteration');
var FORCED_PROMISE_CONSTRUCTOR = require('../internals/promise-constructor-detection').CONSTRUCTOR;

module.exports = FORCED_PROMISE_CONSTRUCTOR || !checkCorrectnessOfIteration(function (iterable) {
NativePromiseConstructor.all(iterable).then(undefined, function () { /* empty */ });
});
14 changes: 8 additions & 6 deletions packages/core-js/modules/es.promise.finally.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
'use strict';
var $ = require('../internals/export');
var IS_PURE = require('../internals/is-pure');
var NativePromise = require('../internals/native-promise-constructor');
var NativePromiseConstructor = require('../internals/promise-native-constructor');
var fails = require('../internals/fails');
var getBuiltIn = require('../internals/get-built-in');
var isCallable = require('../internals/is-callable');
var speciesConstructor = require('../internals/species-constructor');
var promiseResolve = require('../internals/promise-resolve');
var redefine = require('../internals/redefine');

var NativePromisePrototype = NativePromiseConstructor && NativePromiseConstructor.prototype;

// Safari bug https://bugs.webkit.org/show_bug.cgi?id=200829
var NON_GENERIC = !!NativePromise && fails(function () {
var NON_GENERIC = !!NativePromiseConstructor && fails(function () {
// eslint-disable-next-line unicorn/no-thenable -- required for testing
NativePromise.prototype['finally'].call({ then: function () { /* empty */ } }, function () { /* empty */ });
NativePromisePrototype['finally'].call({ then: function () { /* empty */ } }, function () { /* empty */ });
});

// `Promise.prototype.finally` method
Expand All @@ -33,9 +35,9 @@ $({ target: 'Promise', proto: true, real: true, forced: NON_GENERIC }, {
});

// makes sure that native promise-based APIs `Promise#finally` properly works with patched `Promise#then`
if (!IS_PURE && isCallable(NativePromise)) {
if (!IS_PURE && isCallable(NativePromiseConstructor)) {
var method = getBuiltIn('Promise').prototype['finally'];
if (NativePromise.prototype['finally'] !== method) {
redefine(NativePromise.prototype, 'finally', method, { unsafe: true });
if (NativePromisePrototype['finally'] !== method) {
redefine(NativePromisePrototype, 'finally', method, { unsafe: true });
}
}
67 changes: 16 additions & 51 deletions packages/core-js/modules/es.promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ var IS_PURE = require('../internals/is-pure');
var global = require('../internals/global');
var getBuiltIn = require('../internals/get-built-in');
var call = require('../internals/function-call');
var NativePromise = require('../internals/native-promise-constructor');
var NativePromiseConstructor = require('../internals/promise-native-constructor');
var redefine = require('../internals/redefine');
var redefineAll = require('../internals/redefine-all');
var setPrototypeOf = require('../internals/object-set-prototype-of');
Expand All @@ -14,9 +14,7 @@ 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');
Expand All @@ -26,20 +24,19 @@ var newPromiseCapabilityModule = require('../internals/new-promise-capability');
var perform = require('../internals/perform');
var Queue = require('../internals/queue');
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 PromiseConstructorDetection = require('../internals/promise-constructor-detection');
var PROMISE_STATICS_INCORRECT_ITERATION = require('../internals/promise-statics-incorrect-iteration');

var SPECIES = wellKnownSymbol('species');
var PROMISE = 'Promise';

var FORCED_PROMISE_CONSTRUCTOR = PromiseConstructorDetection.CONSTRUCTOR;
var NATIVE_PROMISE_REJECTION_EVENT = PromiseConstructorDetection.REJECTION_EVENT;
var NATIVE_PROMISE_SUBCLASSING = PromiseConstructorDetection.SUBCLASSING;
var getInternalState = InternalStateModule.getterFor(PROMISE);
var setInternalState = InternalStateModule.set;
var getInternalPromiseState = InternalStateModule.getterFor(PROMISE);
var NativePromisePrototype = NativePromise && NativePromise.prototype;
var PromiseConstructor = NativePromise;
var NativePromisePrototype = NativePromiseConstructor && NativePromiseConstructor.prototype;
var PromiseConstructor = NativePromiseConstructor;
var PromisePrototype = NativePromisePrototype;
var TypeError = global.TypeError;
var document = global.document;
Expand All @@ -48,48 +45,16 @@ 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 && !PromisePrototype['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;
Expand Down Expand Up @@ -154,7 +119,7 @@ var dispatchEvent = function (name, promise, 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);
if (!NATIVE_PROMISE_REJECTION_EVENT && (handler = global['on' + name])) handler(event);
else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
};

Expand Down Expand Up @@ -235,7 +200,7 @@ var internalResolve = function (state, value, unwrap) {
};

// constructor polyfill
if (FORCED) {
if (FORCED_PROMISE_CONSTRUCTOR) {
// 25.4.3.1 Promise(executor)
PromiseConstructor = function Promise(executor) {
anInstance(this, PromisePrototype);
Expand Down Expand Up @@ -298,10 +263,10 @@ if (FORCED) {
: newGenericPromiseCapability(C);
};

if (!IS_PURE && isCallable(NativePromise) && NativePromisePrototype !== Object.prototype) {
if (!IS_PURE && isCallable(NativePromiseConstructor) && NativePromisePrototype !== Object.prototype) {
nativeThen = NativePromisePrototype.then;

if (!SUBCLASSING) {
if (!NATIVE_PROMISE_SUBCLASSING) {
// make `Promise#then` return a polyfilled `Promise` for native promise-based APIs
redefine(NativePromisePrototype, 'then', function then(onFulfilled, onRejected) {
var that = this;
Expand All @@ -327,7 +292,7 @@ if (FORCED) {
}
}

$({ global: true, wrap: true, forced: FORCED }, {
$({ global: true, wrap: true, forced: FORCED_PROMISE_CONSTRUCTOR }, {
Promise: PromiseConstructor
});

Expand All @@ -337,7 +302,7 @@ setSpecies(PROMISE);
PromiseWrapper = getBuiltIn(PROMISE);

// statics
$({ target: PROMISE, stat: true, forced: FORCED }, {
$({ target: PROMISE, stat: true, forced: FORCED_PROMISE_CONSTRUCTOR }, {
// `Promise.reject` method
// https://tc39.es/ecma262/#sec-promise.reject
reject: function reject(r) {
Expand All @@ -347,15 +312,15 @@ $({ target: PROMISE, stat: true, forced: FORCED }, {
}
});

$({ target: PROMISE, stat: true, forced: IS_PURE || FORCED }, {
$({ target: PROMISE, stat: true, forced: IS_PURE || FORCED_PROMISE_CONSTRUCTOR }, {
// `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 }, {
$({ target: PROMISE, stat: true, forced: PROMISE_STATICS_INCORRECT_ITERATION }, {
// `Promise.all` method
// https://tc39.es/ecma262/#sec-promise.all
all: function all(iterable) {
Expand Down

0 comments on commit 1ebeeb2

Please sign in to comment.