16

I am having trouble passing all arguments. My promise callback only receives one instead of three:

var asyncFunction= function(resolve) {
    setTimeout(function() {
        resolve("Some string that is passed", "and another", "third");
    }, 1000);
};

var promiseFunction = function () {
    var deferred = Q.defer();

    asyncFunction(deferred.resolve);

    return deferred.promise;
};

promiseFunction().then(function() {
    // Only one argument is passed here instead of 3
    // { '0': 'Some string that is passed' }
    console.log(arguments); 
});

Any idea what I am doing wrong?

Nick
  • 11,483
  • 8
  • 41
  • 44

3 Answers3

13

Q promises can be resolved with only one argument - a promise stands for one single value, not for a collection of them. Put them in an array explicitly if you need multiple values. For the multiple-parameter-callbacks, you can use .spread().

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    how is that possible? There are thousands of libraries with async functions out there that return multiple arguments? Can't they be used then? – Nick Jul 31 '13 at 15:42
  • Only with a wrapper it seems. Do you have a particular one in mind? – Bergi Jul 31 '13 at 15:55
  • @Nick The whole library is centered around the single value approach. [Look at the source](https://github.com/kriskowal/q/blob/424dbd1f8c4a6a40a4b2c341598955b3880bfe79/q.js#L571) and try to figure out what changes would be needed to support multiple values. You'll be surprised how complex this gets while returning little or no real value. Use an array, as Bergi suggests. – Tomalak Jul 31 '13 at 16:05
  • 1
    @Tomalak: I'd say there's a lot of value (my own promise implementation allows it) and passing around `arguments` objects *can* simplify the code. Of course, `Q` was built with a different paradigm from scratch and changing it would be complex now. – Bergi Jul 31 '13 at 16:17
  • @Bergi Hm... If I can use an array to collect multiple values easily and pass them as one object, where is the benefit in allowing multiple parameters in the promise implementation? – Tomalak Jul 31 '13 at 17:33
  • 2
    @Tomalak: You can write more concise callback functions, without accessing properties/indices on the value. Think of the arrays as tuples, not as lists. The [`$.ajax` promises](http://api.jquery.com/jQuery.ajax/#jqXHR) would be a good example. – Bergi Jul 31 '13 at 17:48
  • @Bergi Point taken. You'd have to pass around an object instead of an array to get the benefit of multiple "named arguments" in callback functions with Q. Agreed, that's a slight inconvenience. – Tomalak Jul 31 '13 at 18:06
  • The reason promises only resolve with one value is that they parallel synchronous code. Q can't change it's behavior because, unlike broken libraries that support multiple values, it complies with the [Promises/A+ specification](http://promises-aplus.github.io/promises-spec/) – ForbesLindesay Aug 02 '13 at 10:33
  • 1
    @ForbesLindesay: Actually I don't see A+ forbidding multiple values - I guess we'll have to discuss that at some time, I'll open an issue. And [even synchronous code can return multiple values](http://programmers.stackexchange.com/questions/96168/what-is-the-benefit-of-multiple-return-values) - while currently not allowed in JavaScript (destructuring assignments might give a syntax for that) it is a *feature* in other languages. – Bergi Aug 02 '13 at 13:16
  • Synchronous JavaScript code does not return multiple values. Destructuring assignment is a syntax extension to make it easier to work with functions that return an array of values or an object map of values. That's just like `.spread` is a helper to make it easier to work with functions that return promises for arrays. – ForbesLindesay Aug 02 '13 at 14:48
  • just pass an array or an object with the resolve and you'll be good – RadleyMith Oct 14 '14 at 12:57
2

Synchronous functions return only one value, same way asynchronous should resolve with one.

It's a bad practice to create async functions that resolve with many values. If you want to pass many values, return them in array or dict object, same as you would do if given function would be synchronous.

Mariusz Nowak
  • 32,050
  • 5
  • 35
  • 37
  • 1
    Plenty of libraries using callbacks pass back multiple arguments; I don't consider this bad practice. Promises/Futures supporting multiple values also seems like a logical step. I think this should be explored, as does this [mailing list entry](http://lists.w3.org/Archives/Public/www-dom/2013AprJun/0059.html). – Matt Oct 06 '13 at 05:50
  • Matt, initially in library I maintain I experimented with allowance of multiple values for resolution, but I quickly rejected that idea. I don't remember now the exact issues, but I believe there were cases when I needed to deal with resolved value as one object, and it was weird (and not on par with sync functions) to always deal with an array or arguments object. Decision is already coined and proven to be right in practice. The post you've linked as you see was quickly put down. I don't remember such idea being seriously considered. – Mariusz Nowak Oct 06 '13 at 09:35
  • I only care because I'm writing a promises library (for fun and learning) and multiple resolving arguments feels like such a natural solution to me. If the community has settled on a single value, so be I suppose. Thanks for the follow-up. – Matt Oct 07 '13 at 20:32
  • 2
    @Matt, couldn't agree more. Promises solve the problem of nasty callback nesting yet callbacks still allow for more than one argument passed. It feels quite ridiculous that I can't pass more than one argument to `.resolve`, instead I have to pack it up into an array and unpack it in the callback leading to a mess. Wasn't that what promises was avoiding in the first place, a mess? – AdrianCooney Jan 07 '14 at 02:05
0

If you want to pass along multiple values, you must wrap them in another single value that you pass, such as an array or an object.