Can promises have multiple arguments to onFulfilled?

badunk picture badunk · Apr 1, 2014 · Viewed 105.4k times · Source

I'm following the spec here and I'm not sure whether it allows onFulfilled to be called with multiple arguments. For example:

promise = new Promise(function(onFulfilled, onRejected){
    onFulfilled('arg1', 'arg2');
})

such that my code:

promise.then(function(arg1, arg2){
    // ....
});

would receive both arg1 and arg2?

I don't care about how any specific promises implementation does it, I wish to follow the w3c spec for promises closely.

Answer

Benjamin Gruenbaum picture Benjamin Gruenbaum · Apr 1, 2014

I'm following the spec here and I'm not sure whether it allows onFulfilled to be called with multiple arguments.

Nope, just the first parameter will be treated as resolution value in the promise constructor. You can resolve with a composite value like an object or array.

I don't care about how any specific promises implementation does it, I wish to follow the w3c spec for promises closely.

That's where I believe you're wrong. The specification is designed to be minimal and is built for interoperating between promise libraries. The idea is to have a subset which DOM futures for example can reliably use and libraries can consume. Promise implementations do what you ask with .spread for a while now. For example:

Promise.try(function(){
    return ["Hello","World","!"];
}).spread(function(a,b,c){
    console.log(a,b+c); // "Hello World!";
});

With Bluebird. One solution if you want this functionality is to polyfill it.

if (!Promise.prototype.spread) {
    Promise.prototype.spread = function (fn) {
        return this.then(function (args) {
            return Promise.all(args); // wait for all
        }).then(function(args){
         //this is always undefined in A+ complaint, but just in case
            return fn.apply(this, args); 
        });
    };
}

This lets you do:

Promise.resolve(null).then(function(){
    return ["Hello","World","!"]; 
}).spread(function(a,b,c){
    console.log(a,b+c);    
});

With native promises at ease fiddle. Or use spread which is now (2018) commonplace in browsers:

Promise.resolve(["Hello","World","!"]).then(([a,b,c]) => {
  console.log(a,b+c);    
});

Or with await:

let [a, b, c] = await Promise.resolve(['hello', 'world', '!']);