Skip to content

Commit e287627

Browse files
committedDec 22, 2021
fix the order of calling reactions of fulfilled / rejected promises in Promise.prototype.then, close #1026
1 parent 09db127 commit e287627

File tree

3 files changed

+47
-40
lines changed

3 files changed

+47
-40
lines changed
 

‎CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## Changelog
22
##### Unreleased
3+
- Fixed the order of calling reactions of fulfilled / rejected promises in `Promise.prototype.then`, [#1026](https://github.com/zloirock/core-js/issues/1026)
34
- Fixed some missed dependencies of entries
45
- Added Deno 1.18 compat data mapping
56

‎package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@
116116
"test-entries-content": "zx tests/commonjs-entries-content.mjs",
117117
"test-entries-standalone": "run-s init test-entries",
118118
"test-targets-parser": "zx tests/targets-parser.mjs",
119-
"test": "run-s init test-lint bundle test-unit test-promises-aplus test-observables test-entries test-targets-parser check",
119+
"test": "run-s init test-lint bundle test-unit test-promises test-observables test-entries test-targets-parser check",
120120
"ci-karma": "run-s init bundle test-unit-karma",
121-
"ci-tests": "run-s init bundle test-unit-node test-promises-aplus test-observables test-entries test-targets-parser",
121+
"ci-tests": "run-s init bundle test-unit-node test-promises test-observables test-entries test-targets-parser",
122122
"clean-dependencies": "node scripts/clean-dependencies.mjs",
123123
"refresh": "npm run clean-dependencies && npm it",
124124
"downloads": "zx scripts/downloads-by-versions.mjs",

‎packages/core-js/modules/es.promise.js

+44-38
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var IS_PURE = require('../internals/is-pure');
44
var global = require('../internals/global');
55
var getBuiltIn = require('../internals/get-built-in');
66
var call = require('../internals/function-call');
7+
var uncurryThis = require('../internals/function-uncurry-this');
78
var NativePromise = require('../internals/native-promise-constructor');
89
var redefine = require('../internals/redefine');
910
var redefineAll = require('../internals/redefine-all');
@@ -43,6 +44,7 @@ var PromisePrototype = NativePromisePrototype;
4344
var TypeError = global.TypeError;
4445
var document = global.document;
4546
var process = global.process;
47+
var push = uncurryThis([].push);
4648
var newPromiseCapability = newPromiseCapabilityModule.f;
4749
var newGenericPromiseCapability = newPromiseCapability;
4850

@@ -95,47 +97,50 @@ var isThenable = function (it) {
9597
return isObject(it) && isCallable(then = it.then) ? then : false;
9698
};
9799

100+
var callReaction = function (reaction, state) {
101+
var value = state.value;
102+
var ok = state.state == FULFILLED;
103+
var handler = ok ? reaction.ok : reaction.fail;
104+
var resolve = reaction.resolve;
105+
var reject = reaction.reject;
106+
var domain = reaction.domain;
107+
var result, then, exited;
108+
try {
109+
if (handler) {
110+
if (!ok) {
111+
if (state.rejection === UNHANDLED) onHandleUnhandled(state);
112+
state.rejection = HANDLED;
113+
}
114+
if (handler === true) result = value;
115+
else {
116+
if (domain) domain.enter();
117+
result = handler(value); // can throw
118+
if (domain) {
119+
domain.exit();
120+
exited = true;
121+
}
122+
}
123+
if (result === reaction.promise) {
124+
reject(TypeError('Promise-chain cycle'));
125+
} else if (then = isThenable(result)) {
126+
call(then, result, resolve, reject);
127+
} else resolve(result);
128+
} else reject(value);
129+
} catch (error) {
130+
if (domain && !exited) domain.exit();
131+
reject(error);
132+
}
133+
};
134+
98135
var notify = function (state, isReject) {
99136
if (state.notified) return;
100137
state.notified = true;
101-
var chain = state.reactions;
102138
microtask(function () {
103-
var value = state.value;
104-
var ok = state.state == FULFILLED;
139+
var chain = state.reactions;
105140
var index = 0;
106141
// variable length - can't use forEach
107142
while (chain.length > index) {
108-
var reaction = chain[index++];
109-
var handler = ok ? reaction.ok : reaction.fail;
110-
var resolve = reaction.resolve;
111-
var reject = reaction.reject;
112-
var domain = reaction.domain;
113-
var result, then, exited;
114-
try {
115-
if (handler) {
116-
if (!ok) {
117-
if (state.rejection === UNHANDLED) onHandleUnhandled(state);
118-
state.rejection = HANDLED;
119-
}
120-
if (handler === true) result = value;
121-
else {
122-
if (domain) domain.enter();
123-
result = handler(value); // can throw
124-
if (domain) {
125-
domain.exit();
126-
exited = true;
127-
}
128-
}
129-
if (result === reaction.promise) {
130-
reject(TypeError('Promise-chain cycle'));
131-
} else if (then = isThenable(result)) {
132-
call(then, result, resolve, reject);
133-
} else resolve(result);
134-
} else reject(value);
135-
} catch (error) {
136-
if (domain && !exited) domain.exit();
137-
reject(error);
138-
}
143+
callReaction(chain[index++], state);
139144
}
140145
state.reactions = [];
141146
state.notified = false;
@@ -265,14 +270,15 @@ if (FORCED) {
265270
// https://tc39.es/ecma262/#sec-promise.prototype.then
266271
then: function then(onFulfilled, onRejected) {
267272
var state = getInternalPromiseState(this);
268-
var reactions = state.reactions;
269273
var reaction = newPromiseCapability(speciesConstructor(this, PromiseConstructor));
274+
state.parent = true;
270275
reaction.ok = isCallable(onFulfilled) ? onFulfilled : true;
271276
reaction.fail = isCallable(onRejected) && onRejected;
272277
reaction.domain = IS_NODE ? process.domain : undefined;
273-
state.parent = true;
274-
reactions[reactions.length] = reaction;
275-
if (state.state != PENDING) notify(state, false);
278+
if (state.state == PENDING) push(state.reactions, reaction);
279+
else microtask(function () {
280+
callReaction(reaction, state);
281+
});
276282
return reaction.promise;
277283
},
278284
// `Promise.prototype.catch` method

0 commit comments

Comments
 (0)
Please sign in to comment.