Regarding footnote #2 (promise.then() === promise) #28

blixt opened this Issue Nov 8, 2012 · 3 comments


None yet
2 participants

blixt commented Nov 8, 2012

Should this really be left undefined? It has implications of how third-party libraries may interact. Assume in the code below that we try to be as cheap as possible and return a reference instead of a copy of the promise whenever possible:

// third-party library #1
function doStuff() {
  var promise = ...;
  return promise;

// third-party library #2
function doOtherStuff() {
  // this library augments the doStuff call and returns the result of .then(...)
  var promise = doStuff().then(...);
  return promise;

// my app code
var promise = doOtherStuff();
// additional fail condition in my app fails my reference to promise
if (...) promise.reject();

What will happen above is that "third-party library #2" will think "third-party library #1" failed (but its promise was actually rejected in "my app"), an incorrect assumption. This can lead to the libraries having side-effects that should only ever happen if there was an actual error.

To work around the above problem, the "my app" developer would in this case have to create their own promise and have it resolve or reject whenever the original promise does, in addition to the local fail conditions. This means complicating the app more than is needed. Always returning a copy would never have this problem of disturbing states of promises across application realms.


briancavalier commented Nov 8, 2012

Hey @blixt

Hmmm, I don't quite understand your example. Could you shed a bit more light on what you're getting at? What do you mean by "will think third party library 1 failed" <-- specifically, what does "failed" mean here?

A few thoughts that may help (or not!):

A robust implementation would not (should not, imho) provide a reject or resolve method on the promise directly, so that the promise can be given to any number of parties who are only allowed to observe the result, and not to resolve/reject or otherwise tamper with things.

As a result, the spec is written such that a compliant implementation may allow promise1 === promise2 if and only if it also meets all the other requirements in the spec. Basically, we felt it is not necessary to require a new promise there as long as all other requirements are met, in which case, chaining and forwarding are guaranteed to work, and the Promises/A+ test suite will ensure that.

blixt commented Nov 8, 2012


Sorry, yes your suggestion does make more sense (to not make resolve or reject available on the object itself). I presume you mean creating promises something like this?

var fiveSecondRule = createPromise(function (resolve, reject, progress) {
  food.addEventListener('pickedup', resolve);
  setTimeout(reject, 5000);

I'm in the process of trying to think of all the ways you could implement promises for a big framework used by many libraries and applications at the same time, so just coming up with corner cases.

Thanks for the response, you may close this issue.


briancavalier commented Nov 8, 2012

Right, that's one possible approach. Many current implementations, such as when.js, Q, rsvp, etc. provide a method for creating a {promise, resolver} pair, making it easy to give the promise out to a group of consumers, while either retaining the resolver, or giving it out to a group of producers.

It might also help to have a look at this fairly simple implementation as an example, to see how it structures things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment