Promise.spread "Polyfill" I have written this "Polyfill" for Chrome's Promise object and I have some concerns about the implementation;


Does it actually work as designed? It seems to work but I'm not sure if there are any "edge cases" I am not accounting for.
Is there a better way to do it? The inner function way seems a bit odd, as I don't like how I the promise[method] works.


Here is how the spread method works:

var resolvedArray = Promise.resolve([1, 2, 3]);

resolvedArray.spread(function(a, b, c) {
  console.log(a === 1); // true
  console.log(b === 2); // true
  console.log(c === 3); // true
});

var resolvedOther = Promise.resolve("Hello");

resolvedOther.spread(function(value) {
  console.log(value === "Hello"); // true
});

var rejectedArray = Promise.reject([1, 2, 3]);

rejectedArray.spread(undefined, function(a, b, c) {
  console.log(a === 1); // true
  console.log(b === 2); // true
  console.log(c === 3); // true
});

var rejectedObject = Promise.reject("Hello");

rejectedObject.spread(undefined, function(value) {
  console.log(value === "Hello"); // true
});


And here is my implementation:

Promise.prototype.spread = function() {
  var promise = this;

  var spread = function(promise, method, callback) {
    return promise[method](function(previousValue) {
      if (previousValue instanceof Array) {
        return callback.apply(undefined, previousValue);
      } else {
        return callback.call(undefined, previousValue);
      }
    });
  };

  if (arguments.length &gt;= 1 &amp;&amp; arguments[0] !== undefined) {
    promise = spread(promise, 'then', arguments[0]);
  }

  if (arguments.length &gt;= 2 &amp;&amp; arguments[1] !== undefined) {
    promise = spread(promise, 'catch', arguments[1]);
  }

  return promise;
};
Your implementation is taking .then(a, b) and mapping it to .then(a).catch(b) which is not exactly the same thing.  An exception or return of a rejected promise in a in your implementation will hit the .catch(b), but in .then(a, b), it will not hit b, so I think your .spread() is not correctly imitating the .then() behavior in some circumstances.

Here's my implementation that should more closely mimic .then(a, b):

Promise.prototype.spread = function(a, b) {

    function doSpread(fn) {
        return function(args) {
            if (typeof fn === "function") {
                if (Array.isArray(args)) {
                    return fn.apply(null, args);
                } else {
                    return fn(args);
                }
            } else {
                return args;
            }
        }
    }
    if (typeof b !== "undefined") {
        // there is a reject handler
        return this.then(doSpread(a), doSpread(b));
    } else {
        // no reject handler
        return this.then(doSpread(a));
    }
}

// Array.isArray polyfill
if (!Array.isArray) {
  Array.isArray = function(arg) {
    return Object.prototype.toString.call(arg) === '[object Array]';
  };
}


Working demo and tests: https://jsfiddle.net/jfriend00/nqc0h10y/



And, here's a version that makes the change to wait on any promises that are returned in the array of values per our discussion in comments. I also changed it so that if you don't pass a function to .spread(), it will reject:

Promise.prototype.spread = function(a, b) {

    function doSpread(fn) {
        return function(args) {
            if (typeof fn === "function") {
                if (Array.isArray(args)) {
                    // in cases where there could be promises in the array, wait on those
                    return Promise.all(args).then(function(returnArgs) {
                        // split the array of results into separately passed arguments
                        return fn.apply(null, returnArgs);
                    });
                } else {
                    return fn(args);
                }
            } else {
                throw new Error("Must pass a function to .spread()");
            }
        }
    }
    if (typeof b !== "undefined") {
        // there is a reject handler
        return this.then(doSpread(a), doSpread(b));
    } else {
        // no reject handler
        return this.then(doSpread(a));
    }
}

// Array.isArray polyfill
if (!Array.isArray) {
  Array.isArray = function(arg) {
    return Object.prototype.toString.call(arg) === '[object Array]';
  };
}


Working demo: https://jsfiddle.net/jfriend00/om5auzs0/