Skip to content

Commit

Permalink
Merge pull request #1253 from zloirock/promise-with-resolvers
Browse files Browse the repository at this point in the history
  • Loading branch information
zloirock committed Jun 3, 2023
2 parents d5bf390 + 45bb1c4 commit a91940f
Show file tree
Hide file tree
Showing 13 changed files with 177 additions and 4 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
Expand Up @@ -2,8 +2,8 @@
##### Unreleased
- [Well-formed unicode strings proposal](https://github.com/tc39/proposal-is-usv-string):
- Methods:
- `String.prototype.isWellFormed`
- `String.prototype.toWellFormed`
- `String.prototype.isWellFormed` method
- `String.prototype.toWellFormed` method
- Moved to stable ES, [May 2023 TC39 meeting](https://github.com/tc39/proposal-is-usv-string/pull/31)
- Added `es.` namespace modules, `/es/` and `/stable/` namespaces entries
- [Decorator Metadata proposal](https://github.com/tc39/proposal-decorator-metadata):
Expand All @@ -13,6 +13,8 @@
- [Iterator Helpers Stage 3 proposal](https://github.com/tc39/proposal-iterator-helpers):
- Changed `Symbol.iterator` fallback from callable check to `undefined` / `null` check, May 2023 TC39 meeting, [proposal-iterator-helpers/272](https://github.com/tc39/proposal-iterator-helpers/pull/272)
- Removed `IsCallable` check on `NextMethod`, deferring errors to `Call` site, May 2023 TC39 meeting, [proposal-iterator-helpers/274](https://github.com/tc39/proposal-iterator-helpers/pull/274)
- Added [`Promise.withResolvers` Stage 2 proposal](https://github.com/tc39/proposal-promise-with-resolvers):
- `Promise.withResolvers` method
- [`Symbol` predicates stage 2 proposal](https://github.com/tc39/proposal-symbol-predicates):
- The methods renamed to end with `Symbol`, [May 2023 TC39 meeting](https://github.com/babel/proposals/issues/88#issuecomment-1548219580):
- `Symbol.isRegistered` -> `Symbol.isRegisteredSymbol`
Expand Down
21 changes: 20 additions & 1 deletion README.md
Expand Up @@ -163,6 +163,7 @@ structuredClone(new Set([1, 2, 3])); // => new Set([1, 2, 3])
- [Stage 2 proposals](#stage-2-proposals)
- [`AsyncIterator` helpers](#asynciterator-helpers)
- [`Iterator.range`](#iteratorrange)
- [`Promise.withResolvers`](#promisewithresolvers)
- [`Map.prototype.emplace`](#mapprototypeemplace)
- [`Array.isTemplateObject`](#arrayistemplateobject)
- [`String.dedent`](#stringdedent)
Expand Down Expand Up @@ -1149,7 +1150,7 @@ class Promise {
static reject(r: any): Promise;
static all(iterable: Iterable): Promise;
static allSettled(iterable: Iterable): Promise;
static any(promises: Iterable): Promise<any>;
static any(promises: Iterable): Promise;
static race(iterable: Iterable): Promise;
}
```
Expand Down Expand Up @@ -2512,6 +2513,24 @@ for (const i of Iterator.range(1, 10, { step: 3, inclusive: true })) {
console.log(i); // => 1, 4, 7, 10
}
```
##### [`Promise.withResolvers`](https://github.com/tc39/proposal-promise-with-resolvers)[⬆](#index)
Module [`esnext.promise.with-resolvers`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.promise.with-resolvers.js)
```js
class Promise {
static withResolvers(): { promise: Promise, resolve: function, reject: function };
}
```
[*CommonJS entry points:*](#commonjs-api)
```js
core-js/proposals/promise-with-resolvers
core-js(-pure)/full/promise/with-resolvers
```
[*Examples*](https://tinyurl.com/2gx4t3xu):
```js
const d = Promise.withResolvers();
d.resolve(42);
d.promise.then(console.log); // => 42
```
##### [`Map.prototype.emplace`](https://github.com/thumbsupep/proposal-upsert)[⬆](#index)
Modules [`esnext.map.emplace`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.map.emplace.js) and [`esnext.weak-map.emplace`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.weak-map.emplace.js)
```js
Expand Down
2 changes: 2 additions & 0 deletions packages/core-js-compat/src/data.mjs
Expand Up @@ -2128,6 +2128,8 @@ export const data = {
// TODO: Remove from `core-js@4`
'esnext.promise.try': {
},
'esnext.promise.with-resolvers': {
},
// TODO: Remove from `core-js@4`
'esnext.reflect.define-metadata': {
},
Expand Down
1 change: 1 addition & 0 deletions packages/core-js-compat/src/modules-by-versions.mjs
Expand Up @@ -206,6 +206,7 @@ export default {
'es.string.is-well-formed',
'es.string.to-well-formed',
'esnext.function.metadata',
'esnext.promise.with-resolvers',
'esnext.symbol.is-registered-symbol',
'esnext.symbol.is-well-known-symbol',
],
Expand Down
3 changes: 2 additions & 1 deletion packages/core-js/full/promise/index.js
@@ -1,6 +1,7 @@
var parent = require('../../actual/promise');
require('../../modules/esnext.aggregate-error');
require('../../modules/esnext.promise.with-resolvers');
// TODO: Remove from `core-js@4`
require('../../modules/esnext.aggregate-error');
require('../../modules/esnext.promise.all-settled');
require('../../modules/esnext.promise.try');
require('../../modules/esnext.promise.any');
Expand Down
13 changes: 13 additions & 0 deletions packages/core-js/full/promise/with-resolvers.js
@@ -0,0 +1,13 @@
'use strict';
require('../../modules/es.promise');
require('../../modules/esnext.promise.with-resolvers');
var call = require('../../internals/function-call');
var isCallable = require('../../internals/is-callable');
var path = require('../../internals/path');

var Promise = path.Promise;
var promiseWithResolvers = Promise.withResolvers;

module.exports = { withResolvers: function withResolvers() {
return call(promiseWithResolvers, isCallable(this) ? this : Promise);
} }.withResolvers;
16 changes: 16 additions & 0 deletions packages/core-js/modules/esnext.promise.with-resolvers.js
@@ -0,0 +1,16 @@
'use strict';
var $ = require('../internals/export');
var newPromiseCapabilityModule = require('../internals/new-promise-capability');

// `Promise.withResolvers` method
// https://github.com/tc39/proposal-promise-with-resolvers
$({ target: 'Promise', stat: true, forced: true }, {
withResolvers: function withResolvers() {
var promiseCapability = newPromiseCapabilityModule.f(this);
return {
promise: promiseCapability.promise,
resolve: promiseCapability.resolve,
reject: promiseCapability.reject
};
}
});
2 changes: 2 additions & 0 deletions packages/core-js/proposals/promise-with-resolvers.js
@@ -0,0 +1,2 @@
// https://github.com/tc39/proposal-promise-with-resolvers
require('../modules/esnext.promise.with-resolvers');
1 change: 1 addition & 0 deletions packages/core-js/stage/2.js
Expand Up @@ -5,6 +5,7 @@ require('../proposals/async-explicit-resource-management');
require('../proposals/async-iterator-helpers');
require('../proposals/iterator-range');
require('../proposals/map-upsert-stage-2');
require('../proposals/promise-with-resolvers');
require('../proposals/string-dedent');
require('../proposals/symbol-predicates-v2');
// TODO: Obsolete versions, remove from `core-js@4`
Expand Down
3 changes: 3 additions & 0 deletions tests/compat/tests.js
Expand Up @@ -1703,6 +1703,9 @@ GLOBAL.tests = {
'esnext.observable.of': function () {
return Observable.of;
},
'esnext.promise.with-resolvers': [PROMISES_SUPPORT, function () {
return Promise.withResolvers;
}],
'esnext.set.add-all': function () {
return Set.prototype.addAll;
},
Expand Down
2 changes: 2 additions & 0 deletions tests/entries/unit.mjs
Expand Up @@ -808,6 +808,7 @@ for (PATH of ['core-js-pure', 'core-js']) {
ok(typeof load(NS, 'reflect/has-own-metadata') == 'function');
ok(typeof load(NS, 'reflect/metadata') == 'function');
ok(load(NS, 'promise/try')(() => 42) instanceof load(NS, 'promise'));
ok(load(NS, 'promise/with-resolvers')().promise instanceof load(NS, 'promise'));
ok(load(NS, 'set/add-all')(new Set([1, 2, 3]), 4, 5).size === 5);
ok(load(NS, 'set/delete-all')(new Set([1, 2, 3]), 4, 5) === false);
ok(load(NS, 'set/every')(new Set([1, 2, 3]), it => typeof it == 'number'));
Expand Down Expand Up @@ -940,6 +941,7 @@ for (PATH of ['core-js-pure', 'core-js']) {
load('proposals/promise-any');
load('proposals/promise-finally');
load('proposals/promise-try');
load('proposals/promise-with-resolvers');
load('proposals/reflect-metadata');
load('proposals/regexp-dotall-flag');
load('proposals/regexp-named-groups');
Expand Down
56 changes: 56 additions & 0 deletions tests/unit-global/esnext.promise.with-resolvers.js
@@ -0,0 +1,56 @@
const { getPrototypeOf } = Object;

QUnit.test('Promise.withResolvers', assert => {
const { withResolvers } = Promise;
assert.isFunction(withResolvers);
assert.arity(withResolvers, 0);
assert.name(withResolvers, 'withResolvers');
assert.nonEnumerable(Promise, 'withResolvers');
assert.looksNative(withResolvers);

const d1 = Promise.withResolvers();
assert.same(getPrototypeOf(d1), Object.prototype, 'proto is Object.prototype');
assert.true(d1.promise instanceof Promise, 'promise is promise');
assert.isFunction(d1.resolve, 'resolve is function');
assert.isFunction(d1.reject, 'reject is function');

const promise = {};
const resolve = () => { /* empty */ };
let reject = () => { /* empty */ };

function P(exec) {
exec(resolve, reject);
return promise;
}

const d2 = withResolvers.call(P);
assert.same(d2.promise, promise, 'promise is promise #2');
assert.same(d2.resolve, resolve, 'resolve is resolve #2');
assert.same(d2.reject, reject, 'reject is reject #2');

reject = {};

assert.throws(() => withResolvers.call(P), TypeError, 'broken resolver');
assert.throws(() => withResolvers.call({}), TypeError, 'broken constructor #1');
assert.throws(() => withResolvers.call(null), TypeError, 'broken constructor #2');
});

QUnit.test('Promise.withResolvers, resolve', assert => {
const d = Promise.withResolvers();
d.resolve(42);
return d.promise.then(it => {
assert.same(it, 42, 'resolved as expected');
}, () => {
assert.avoid();
});
});

QUnit.test('Promise.withResolvers, reject', assert => {
const d = Promise.withResolvers();
d.reject(42);
return d.promise.then(() => {
assert.avoid();
}, error => {
assert.same(error, 42, 'rejected as expected');
});
});
55 changes: 55 additions & 0 deletions tests/unit-pure/esnext.promise.with-resolvers.js
@@ -0,0 +1,55 @@
import Promise from 'core-js-pure/full/promise';
import getPrototypeOf from 'core-js-pure/es/object/get-prototype-of';

QUnit.test('Promise.withResolvers', assert => {
const { withResolvers } = Promise;
assert.isFunction(withResolvers);
assert.arity(withResolvers, 0);
assert.name(withResolvers, 'withResolvers');

const d1 = Promise.withResolvers();
assert.same(getPrototypeOf(d1), Object.prototype, 'proto is Object.prototype');
assert.true(d1.promise instanceof Promise, 'promise is promise');
assert.isFunction(d1.resolve, 'resolve is function');
assert.isFunction(d1.reject, 'reject is function');

const promise = {};
const resolve = () => { /* empty */ };
let reject = () => { /* empty */ };

function P(exec) {
exec(resolve, reject);
return promise;
}

const d2 = withResolvers.call(P);
assert.same(d2.promise, promise, 'promise is promise #2');
assert.same(d2.resolve, resolve, 'resolve is resolve #2');
assert.same(d2.reject, reject, 'reject is reject #2');

reject = {};

assert.throws(() => withResolvers.call(P), TypeError, 'broken resolver');
assert.throws(() => withResolvers.call({}), TypeError, 'broken constructor #1');
assert.throws(() => withResolvers.call(null), TypeError, 'broken constructor #2');
});

QUnit.test('Promise.withResolvers, resolve', assert => {
const d = Promise.withResolvers();
d.resolve(42);
return d.promise.then(it => {
assert.same(it, 42, 'resolved as expected');
}, () => {
assert.avoid();
});
});

QUnit.test('Promise.withResolvers, reject', assert => {
const d = Promise.withResolvers();
d.reject(42);
return d.promise.then(() => {
assert.avoid();
}, error => {
assert.same(error, 42, 'rejected as expected');
});
});

0 comments on commit a91940f

Please sign in to comment.