80

Situation

I have the following function which uses Promise.

var getDefinitions = function() {
    return new Promise(function(resolve) {
        resolve(ContactManager.request("definition:entities"));
    });
}

var definitions = getDefinitions()

The contents of definitions is:

Promise {
    [[PromiseStatus]]: "resolved",
    [[PromiseValue]]: child
}

Accessing the PromiseValue property directly returns undefined

var value = definitions.PromiseValue; // undefined

Question

What do the double brackets [[ ]] mean, and how do I retrieve the value of [[PromiseValue]].

Bram Verstraten
  • 1,414
  • 11
  • 24
Jeff
  • 3,943
  • 8
  • 45
  • 68
  • 2
    It would help to know which library you're using. – JJJ Mar 07 '15 at 15:53
  • 5
    Umm, I think I'm using the built in javascript library with Chrome (??) – Jeff Mar 07 '15 at 15:55
  • `getDefinitions()` is not a built-in function. – JJJ Mar 07 '15 at 15:55
  • ok that's my function, i've added that in the edit. – Jeff Mar 07 '15 at 15:56
  • Just randomly guessing, but have you tried: `definitions.[[PromiseValue]]`? – watery Mar 07 '15 at 15:56
  • yeah. `definitions.[[PromiseValue]];` returns a syntax error. – Jeff Mar 07 '15 at 15:58
  • What "javascript console" are we talking about here (like, what browser/other environment)? Are you using the `console` API to print things out? – Pointy Mar 07 '15 at 16:00
  • 2
    It looks like it's just how the promise state is described. You can try this in the console of Chrome : `new Promise(function(){})`. The `[[PromiseStatus]]` of Chrome can be compared to the `` of Firefox. I don't really get what's the question is here (providing OP knows what a promise is). – Denys Séguret Mar 07 '15 at 16:00
  • @pointy. I'm using chrome's built in console – Jeff Mar 07 '15 at 16:02
  • 1
    @Jeff as far as I can tell, that's just how Chrome shows you the state of the promise. Those properties are deliberately not visible external to the object. If you look at a Promise object in Firefox, it doesn't present it that way. I think it's probably just intended to be a diagnostic aid. – Pointy Mar 07 '15 at 16:04
  • @pointy Ok I think that makes sense. I guess I need to look more at promises documentation to figure out how to the get the PromiseValue – Jeff Mar 07 '15 at 16:05
  • This might be what I need: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve – Jeff Mar 07 '15 at 16:06
  • Can we close this question ? – Denys Séguret Mar 07 '15 at 16:07
  • I guess, except I still haven't figured out how to get the value -- still I think that is a different question now, so go ahead a close it. – Jeff Mar 07 '15 at 16:10
  • 1
    What's `ContactManager.request("definition:entities")`? – Benjamin Gruenbaum Mar 07 '15 at 16:28
  • @watery: If at all, it would need to be `definitions["[[PromiseValue]]"]` – Bergi Mar 07 '15 at 16:33
  • https://github.com/rossberg-chromium/js-promise/blob/master/promise.js , https://github.com/domenic/promises-unwrapping/blob/master/README.md , https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol – guest271314 Mar 09 '15 at 03:14
  • @dystroy I think it's a worthwhile question that other people are bound to wonder about. [at]Jeff - The short answer is that you would get the value using the promise's `.this()` method or one of a handful of helper functions. Pretty much any tutorial on promises will explain this so if you are not yet familiar with promises I suggest getting familiar with them. – JLRishe Mar 09 '15 at 05:06

7 Answers7

108

What's the stuff inside [[]]

My question is what do the double brackets [[ ]] mean, and how do I retrieve the value of [[PromiseValue]].

It's an internal property. You cannot access it directly. Native promises may only be unwrapped in then with promises or asynchronously in generally - see How to return the response from an asynchronous call. Quoting the specification:

They are defined by this specification purely for expository purposes. An implementation of ECMAScript must behave as if it produced and operated upon internal properties in the manner described here. The names of internal properties are enclosed in double square brackets [[ ]]. When an algorithm uses an internal property of an object and the object does not implement the indicated internal property, a TypeError exception is thrown.

You cannot

Seriously though - what are they?

Very nice! As the above quote says they're just used in the spec - so there is no reason for them to really appear in your console.

Don't tell anyone but these are really private symbols. The reason they exist is for other internal methods to be able to access [[PromiseValue]]. For example when io.js decides to return promises instead of taking callbacks - these would allow it to access these properties fast in cases it is guaranteed. They are not exposed to the outside.

Can I access them?

Not unless you make your own Chrome or V8 build. Maybe in ES7 with access modifiers. As of right now, there is no way as they are not a part of the specification and will break across browsers - sorry.

So how do I get my value?

getDefinitions().then(function(defs){
    //access them here
});

But what if it returns an error? In prevision towards these cases, add the following at the end (and outside of) of your .then().

.catch(function(defs){
    //access them here
});

Although if I had to guess - you're not converting the API correctly to begin with since this conversion would only work in case the method is synchronous (in that case don't return a promise) or it returns a promise already which will make it resolved (which means you don't need the conversion at all - just return.

GiselleMtnezS
  • 105
  • 1
  • 2
  • 13
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • In addition it should be said that it completely runs counter the purpose of a `Promise` to access its wrapped value outside of `then`. The purpose of a `Promise` is to abstract from the missing return value of a non-blocking function that is, a `Promise` represents a "future value". Once one would expose this "future value" (outside of `then`), these abstraction would be lost immediately for the whole computation. –  Jul 10 '16 at 08:50
  • If the promise is rejected then the values will be available through `.catch((values) => {})` rather than in `.then(() => {})` – jony89 Aug 11 '17 at 13:59
  • @Benjamin, did you meant that internal slots and internal methods are implemented by JS engine in accordance to spec ? I read one [answer](https://stackoverflow.com/a/33076181/2844702) which said, they are just words and have no implementation. (May be I am misunderstanding here) Also, I am not asking in context of promises as i have not much idea on it right now. Just asking generally like [[PUT]] [[Prototype]] etc – Number945 Feb 06 '20 at 09:59
  • @Number945 generally, `[[PromiseValue]]` in the devtools is actually generated by the devtools - when you press enter on the console it does a [`evaluateOnCallFrame`](https://chromedevtools.github.io/devtools-protocol/tot/Debugger/#method-evaluateOnCallFrame), sends the message over to V8 which returns a RemoteObject of subtype `promise`. There is explicit ad-hoc support for this to work. The above answer is correct (that's where the inspector gets these properties from) but not accurate (that's not how they get there - they get there via explicit debugger support) – Benjamin Gruenbaum Jun 06 '20 at 21:20
18

I also walked into this problem today and happened to find a solution.

My solution looks like this:

fetch('http://localhost:3000/hello')
.then(dataWrappedByPromise => dataWrappedByPromise.json())
.then(data => {
    // you can access your data here
    console.log(data)
})

Here, dataWrappedByPromise is a Promise instance. To access the data in the Promise instance, I found that I just needed to unwrap that instance with the .json() method.

Hope that helps!

cafemike
  • 660
  • 5
  • 16
  • because of currying `then(dataWrappedByPromise => dataWrappedByPromise.json())` === `then(resp.json())` – jymbob Jul 31 '18 at 09:27
  • @jymbob I can't make sense of your comment. You say that where cafemike defines an arrow function, that definition can be replaced by a constant; specifically, you say that his "then()" is equivalent to "then(resp.json())". Firstly, where did "resp" come from? More importantly, the argument "resp.json()" executes immediately, so the argument passed to ".then()" is whatever constant (string, object, or number) results from executing while the promise is still unresolved. Maybe you don't understand that ".then()" expects a function as its argument. – IAM_AL_X Apr 06 '20 at 21:06
  • @IAM_AL_X huh. I can't make sense of my comment either. The only thing I can think two years later is I meant to refer to the "console.log" line and completely mistyped. It holds true that `.then(data => { console.log(data)})` can be simplified to `.then(console.log)` but you're absolutely right that the function is needed to access a constant on that function. Sorry for any confusion – jymbob Apr 15 '20 at 11:11
5

This example is with react but for the most part it should be the same.

Replace this.props.url with your url to fetch to make it work for most other frameworks.

Parsing the res.json() returns the [[promiseValue]] however if you then return it to another .then() method below you can return it as a total array.

let results = fetch(this.props.url)
        .then((res) => {
            return res.json();
        })
        .then((data) => {
            return data;
        })
Lachlan Young
  • 1,266
  • 13
  • 15
1

Try using await.

Instead of

var value = definitions.PromiseValue 

use

var value =  await definiton;

This might solve your purpose by yielding the promise value.

Note that await can only be used inside async functions, and it is an ES2016 feature.

FZs
  • 16,581
  • 13
  • 41
  • 50
0

Reading the manpage, we can see that:

By design, the instant state and value of a promise cannot be inspected synchronously from code, without calling the then() method.

To help with debugging, only when inspecting a promise object manually, you can see more information as special properties that are inaccessible from code (this, at present, is implemented by randomizing the property name, for the lack of more sophisticated language or debugger support).

Emphasis mine. Therefore, what you want to do cannot be done. The better question is why do you need to access the promise state like that?

Etheryte
  • 24,589
  • 11
  • 71
  • 116
-1

I think that it will go well with this.

(async () => {
  let getDefinitions = await ( () => {
    return new Promise( (resolve, reject) => {
      resolve(ContactManager.request("definition:entities"));
    });
  })();
)();
-4

For the case when the response returned is HTML, not a JSON

fetch('http://localhost:3000/hello')
  .then(response => response.text())
  .then(data => {
    // you can see your PromiseValue data here
    console.log(data)
  })
Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140