kriskowal / q

A promise library for JavaScript
MIT License
14.93k stars 1.2k forks source link

Promise.valueOf() returns a promise, not the value of the promise. #237

Closed Redsandro closed 11 years ago

Redsandro commented 11 years ago

I cannot get the value out of a promise. valueOf seems to be the way to do this, but it is either broken or I misunderstood how to use it.

Testcase q.valueof.js

#!/usr/bin/env node

var util    = require('util'),
    q       = require('q');

util.debug('Test promise.valueOf()...');

var someFunction = function(val, cb){cb(null, val);};
var someValue = 'shiboleet';
var myPromise = q.nfcall(someFunction, someValue).then(function(val){
    util.debug('Expect: "shiboleet" (1)');
    util.log(val); // String: shiboleet
    return val;
});

util.debug('Expect: "shiboleet" (2)');
util.log(myPromise.valueOf()); // Object: Promise

Terminal output

$ ./q.valueof.js 
DEBUG: Test promise.valueOf()...
DEBUG: Expect: "shiboleet" (2)
19 Mar 18:34:43 - [object Promise]
DEBUG: Expect: "shiboleet" (1)
19 Mar 18:34:43 - shiboleet
Redsandro commented 11 years ago

This is happening to all promises, not just the once created by q.nfcall. I first encountered this trying to get an array from promise.allResolved(). I get a promise, even in the valueOf that promise. I can traverse the array inside the promise chain (then()), but then the array items are promises for which I cannot reach their values.

Once a starship is returned as a promise, there is no escape from the chain. We are trying to reach our home world, which lies outside the chain. Please show us how to correctly change our heading. We are desperate for food and supplies.

Redsandro commented 11 years ago

I now realize that a promise that not is fulfilled yet cannot reveal it's value, but I am wondering if the valueOf() shouldn't be undefined in this case.

kriskowal commented 11 years ago

@redsandro Tough call. undefined is a perfectly meaningful fulfillment value, but a promise is not.

Redsandro commented 11 years ago

Hmm.. this is true. Back when things took time in my node script, I was getting used to being able to use valueOf() so that I forgot to check that this is actually documented in the API wiki.

I guess in stead of checking for undefined I can do something like if (myPromise.valueOf().constructor && myPromise.valueOf().constructor.name == 'Promise') for now, and start converting all such occurances in my code to a callback-stype wrapper functions to pass along promised values.

kriskowal commented 11 years ago

Use !promise.isPending() as your guard. Generally though, use "then" unless you really need to optimize.

On Tuesday, March 19, 2013, Redsandro wrote:

Hmm.. this is true. Back when things took time in my node script, I was getting used to being able to use valueOf() that I forgot to check that this is actually documented in the API wiki.

I guess in stead of checking for undefined I can do something like if (myPromise.valueOf().constructor && myPromise.valueOf().constructor.name== 'Promise')for now, and start converting all such occurances in my code to a callback-stype wrapper functions to pass along promised values.

— Reply to this email directly or view it on GitHubhttps://github.com/kriskowal/q/issues/237#issuecomment-15151588 .

Redsandro commented 11 years ago

Thank you.

domenic commented 11 years ago

To be fair, there's some agreement that the existing synchronous-inspection mechanisms are confusing, and might be replaced or augmented with something like https://github.com/promises-aplus/synchronous-inspection-spec/issues/6

Redsandro commented 11 years ago

I agree that this could be improved upon, but in my own prosecution, one might argue that in an ideal promised land, values won't ever have to be evaluated like this.

Either way, I like that this is being debated. :)

Redsandro commented 11 years ago

One thing though about events in stead of promises is that breakpoint debugging is a great way to examine long storylines of code. But the value of a promise in an entire chain cannot be followed in a similar fashion this way, because the value won't be known until a few ticks later.

Any hints on how to do something similar in promiseland?