Promise.cast and Promise.resolve

Domenic Denicola domenic at
Tue Jan 28 11:13:00 PST 2014

I am hesitant to retread, but I suppose we should clear up the confusion of the last few messages.

Indeed, things evolved slightly since the last consensus, to the point where the solution that made the most sense was to store the promise's resolution value (whatever it may be) then do the unwrapping entirely inside `then`. So effectively, `Promise.resolve` is now what `Promise.fulfill` used to be; however, because `then` unwraps, in practice `then` users will not notice a difference (i.e. promises for promises are not observable). ES7-timeframe monad additions to the standard library could indeed make use of the stored resolution value.

To bring things down to earth more:

The following code will retain GC references to all of the variables, including `p2`, `p3`, and `p4`:

var p1 = Promise.cast(1);
var p2 = Promise.resolve(gcRoot.p1);
var p3 = Promise.resolve(p2);
gcRoot.p4 = Promise.resolve(p3);

`gcRoot.p4` maintains a reference to `p3`, which maintains a reference to `p2`, which maintains a reference to `p1`.

Whereas, given

var p1 = Promise.cast(1);
var p2 = Promise.cast(gcRoot.p1);
var p3 = Promise.cast(p2);
gcRoot.p4 = Promise.cast(p3);

we have that all the variables are equal, i.e. `p1 === p2`, `p2 === p3`, and `p3 === gcRoot.p4`.


With all that said, I somewhat agree with the sentiment of the OP that `Promise.resolve` is pointless, and even (from a memory consumption POV), a footgun. However, we settled on keeping it, based on a few weak arguments:

- Symmetry with `Promise.reject(r)` ≈ `new Promise((resolve, reject) => reject(r))`; we should also have `Promise.resolve(x)` ≈ `new Promise((resolve, reject) => resolve(x))`.
- Sometimes you want to guarantee object non-identity so a shorthand is useful (Tab Atkins had some use case involving CSS specs).

You can peruse the issue tracker for more discussion. We're certainly retreading old ground here.

More information about the es-discuss mailing list