7

Can someone explain to me why the resulting promise (d) from the code below is resolved immediately?

//promises that are never resolved nor rejected
var a = new Promise(function(r,re){});
var b = new Promise(function(r,re){});
var c = new Promise(function(r,re){});

var d = [a, b, c].reduce(function (previousPromise, promise) {
    return previousPromise.then(promise);
  }, Promise.resolve());

I'm creating an array of promises that are pending forever, so the resulting promise should also be pending forever as it waits for all subsequent promises to finish (as presented here). I've been using promises for a while now, but I'm clearly missing something here.

Chrome DevTools - promises code executed

Amit
  • 45,440
  • 9
  • 78
  • 110
Konrad Dzwinel
  • 36,825
  • 12
  • 98
  • 105

2 Answers2

10

then doesn't take a Promise as an input, it takes 2 functions, 1 for fulfillment and 1 for rejection.

The reason d is resolved is due to the fact that calling .then with a non-callable value (even a number literal - 1, or undefined) causes the onFulfilled function to be replace by "Identity", which simply re-fulfills with whatever value was resolved in the previous step. See PerformPromiseThen

Try like this:

//promises that are never resolved nor rejected
var a = function() { return new Promise(function(r,re){}); };
var b = function() { return new Promise(function(r,re){}); };
var c = function() { return new Promise(function(r,re){}); };
// or simply, a = b = c after setting the function for c

var d = [a, b, c].reduce(function (previousPromise, fn) {
    return previousPromise.then(fn, /* not passing a rejection handler... */);
  }, Promise.resolve());

Or alternatively...

//promises that are never resolved nor rejected
var a = new Promise(function(r,re){});
var b = new Promise(function(r,re){});
var c = new Promise(function(r,re){});

var d = [a, b, c].reduce(function (previousPromise, promise) {
    return previousPromise.then(function() {return promise;});
  }, Promise.resolve());

And since you're using promises & ES6, you could be more concise:

let a = new Promise(() => {});
let b = new Promise(() => {});
let c = new Promise(() => {});

let d = [a, b, c].reduce((previousPromise, promise) =>
  previousPromise.then(() => promise),
  Promise.resolve());
Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
Amit
  • 45,440
  • 9
  • 78
  • 110
  • How come `Promise.resolve().then(new Promise(function(r, re) {}))` resolves to a pending promise? – CodingIntrigue Aug 18 '15 at 09:00
  • @RGraham it doesn't really – Jaromanda X Aug 18 '15 at 09:06
  • It is 'pending' for a split second while the `new Promise(...)` waits to be executed. As Promise handlers are executed asynchronously Chrome will log the Promise immediately, but if you assign the Promise to a variable and _then_ log it, you will see it is resolved. – sdgluck Aug 18 '15 at 09:11
  • @sdgluck No, I tried that too. http://i.imgur.com/v7ATbeq.png. .@Amit That's what I assumed. Although I see why this answers the question, I'm not sure how the OP is getting a resolved promise from their code because I'm not. – CodingIntrigue Aug 18 '15 at 09:13
  • no, you're right ... but I don't fully understand it to be honest, but the `Promise.resolve();` logs fulfilled, whereas `Promise.resolve().then()` is pending because the `then` is executed in the next event loop or something ... it does my head in trying to think about it to be honest – Jaromanda X Aug 18 '15 at 09:13
  • @sdgluck Ha! I'll have to do some investigating on my side. Still can't replicate that here. – CodingIntrigue Aug 18 '15 at 09:16
  • 3
    calling `.then` with a non-callable value (even a number literal - `1`) causes the onFulfilled function to be replace by "Identity", which simply re-fulfills with whatever value was resolved in the previous step. See [PerformPromiseThen](http://www.ecma-international.org/ecma-262/6.0/#sec-performpromisethen) – Amit Aug 18 '15 at 09:18
  • @RGraham in the console, compare this - `d = Promise.resolve('stuff').then(); d` with `d = Promise.resolve('stuff').then();` (on a new line just type `d`) ... – Jaromanda X Aug 18 '15 at 09:20
  • @Amit - this question makes sense now! – Jaromanda X Aug 18 '15 at 09:22
  • @JaromandaX - You're right, I should (and will!) add this last part to the answer itself... – Amit Aug 18 '15 at 09:23
-1
var d = [a, b, c].reduce(function (previousPromise, promise) {
    return previousPromise.then(promise);
}, Promise.resolve());

Your initial state of d promise is resolved, you set is as Promise.resolve(). Check documentation of reduce https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

Maxx
  • 1,740
  • 10
  • 17
  • This is incorrect. A Promise's fulfilment or rejection does not waterfall and affect a subsequent Promise's status. – sdgluck Aug 18 '15 at 09:05