2

What does the ECMAScript 6.0 specification say about a Promise resolving another Promise? Should it adopt the state of the other Promise by attaching a then to that Promise which would resolve this one?

I tried this snippet in Chrome and here is what I get and it seems to just resolve the Promise1 with Promise2 is that fine?

> Promise1 = new Promise(function(resolve){ResolveYouLater1 = resolve})
> Promise2 = new Promise(function(resolve){ResolveYouLater2 = resolve})
> ResolveYouLater1(Promise2)
  undefined
> Promise1
  Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Promise}

I thought it should attach a then to Promise2 which should ResolveYouLater1(value) when Promise2 is the settled.

Nishant
  • 20,354
  • 18
  • 69
  • 101
  • 1
    Please don't be fooled by the output of internal members on the console. Promise1 will settle with the same value as Promise2. It didn't fulfill yet. It's [resolved](http://stackoverflow.com/a/29269515/1048572) with the other promise for now, and that's fine. – Bergi Jan 23 '16 at 15:01
  • Why would the Chrome console give me this value? Is there a reason for that? I will try it out in node.js. Also you mean that it would attach a then to Promise right (as mentioned later in second scenario)? Further, when will the then of Promise1 be triggered since you said it will resolved with the other Promise. – Nishant Jan 23 '16 at 15:02
  • 1
    You can try to replace `Promise2.then` with an interceptor (that logs a message) before calling `ResolveYouLater1(Promise2)`, and you should see how it attaches a handler. – Bergi Jan 23 '16 at 15:04

1 Answers1

2

What does the ECMAScript 6.0 specification say about a Promise resolving another Promise?

You can read it yourself here: http://www.ecma-international.org/ecma-262/6.0/#sec-promise-resolve-functions
When the argument is a thenable, a PromiseResolveThenableJob will be queued.

Should it adopt the state of the other Promise by attaching a then to that Promise which would resolve this one?

Yes. The .then() method will be called with a resolver and rejecter function.

I tried this snippet in Chrome and here is what I get and it seems to just resolve the Promise1 with Promise2 is that fine?

Yes. It's only resolved for now.


I do have to admit, my current Chrome Version (48.0.2564.82, V8 4.8.271.17) doesn't exactly comply to this algorithm (which might not be a bad thing per se, and avoids memory problems, but can be unexpected).
It is lazy, and only schedules the job once an actual callback is interested in the result. And it doesn't pass a resolver to the then method, but the actual callback that wants to know the result.

> var resolve1, resolve2;
> var promise1 = new Promise(function(r){ resolve1 = r; });
> var promise2 = new Promise(function(r){ resolve2 = r; });
> promise2.then = function(...args) { console.log(...args);
>                                     return Promise.prototype.then.call(this, ...args); };
> resolve1(promise2);
  undefined
// you'd expected a call to the then method here
> promise1
  Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Promise}
> promise2
  Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
> resolve2(42)
  undefined
// or at least here
> promise1
  Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Promise}
> promise2
  Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 42}
> promise1.then(x => console.log(x))
  x => console.log(x), PromiseIdRejectHandler() { [native code] }
  // but it only is here
  42
  Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
> promise2.then(x => console.log(x))
  x => console.log(x)
  42
  Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
> promise1.then(x => console.log(x))
  x => console.log(x), PromiseIdRejectHandler() { [native code] }
// hell they're even calling it multiple times!
42
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}

> var resolve1, resolve2;
> var promise1 = new Promise(function(r){ resolve1 = r; });
> var thenable = {then:function(r) { console.log(...arguments); resolve2 = r; }};
> resolve1(thenable);
  undefined
// you'd expected a call to the then method here
> promise1
  Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Object}
> thenable
  Object {}
> resolve2(42)
  Uncaught TypeError: resolve2 is not a function(…)
// uh. yeah.
> promise1.then(x => console.log(x))
  () { [native code] }, () { [native code] }
// ah there was the call, even with a resolver
  Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
> resolve2(42)
  42
  undefined
> promise1.then(x => console.log(x))
  () { [native code] }, () { [native code] }
// but now they fucked up.
// Instead of another call on the thenable, you'd expected the result to be logged
  Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
> resolve2(42)
  42
// OMG.
  undefined
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Brilliant. I will go through this! – Nishant Jan 23 '16 at 15:32
  • Also I added the return the new then method, so that it chains correctly. I was trying it out and found this missing. Please let me know if thats not correct or anything as I am pretty new. – Nishant Jan 25 '16 at 10:50
  • 1
    Yes, adopting another promise means that both resolve to the same value, and the promises are pretty much indistinguishable then. Adopting thenable is done by passing the `resolve` and `reject` callbacks that settle the promise to the `then()` method. Delegating all `then` calls like Chrome does it is not spec-conforming. – Bergi Jan 25 '16 at 14:09
  • 1
    That `return` isn't wrong, although we didn't really need it here, I was never chaining to `.then()` in the example. It only changes one result. – Bergi Jan 25 '16 at 14:11
  • (Treat this as Comment 2 - Fixed a typo and re-added) . Isn't it almost like promise1.then is delegating its work to promise2.then and passing the resolve handle of the new Promise created by promise1.then say promise3? So there is a resolve3 (resolve of promise3) and callback sent over to promise2.then. If promise2 is resolved state everything happens immediately, if not resolved already, it stores it up for future use. Its interesting that Chrome does it Lazy way which I kind of think is nice. Now if promise1.then already exists then its not lazy in somesense. – Nishant Jan 25 '16 at 15:14