How do I resolve an infinite Javascript promise? - javascript

I'm using the Apollo GraphQL library, and at one point it returns a promise. I can see that it's a resolved promise when I inspect it in the console:
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Object}
__proto__
:
Promise
[[PromiseStatus]]
:
"resolved"
[[PromiseValue]]
:
Object
However, when I Promise.resolve(thatPromise) I get back ... the same promise. No matter how many times I resolve the promise, it keeps returning a promise, making it impossible to access the promise's value.
I know the value is in there (if I inspect [[PromiseValue]] it's a plain object with values) ... I just can't figure out how to get it out at the code level instead of in the browser console.
Has anyone ever run in to something like this, and if so were you able to figure out how to extract the value of such an infinitely resolving promise?
P.S. I did try:
thatPromise['[[PromiseValue]]'];
but it appears to be a special browser value that you can't access from the code.
P.P.S. Just realized it may or may not actually be a promise. I get it by calling response.clone().json(), so while it looks like a promise maybe it's just a clone of a promise, in which case that might explain why I can't resolve it. However, it doesn't explain how I can extract the value.
EDIT
I think there's weirdness going on here and I'm not reporting all of the relevant details. Will post more info as soon as I sort things out better (don't want to send anyone on a wild goose chase).

There's no reason for you to have to call Promise.resolve to get the value. Remember that Promises are asynchronous. You have to access it's value like this:
myPromise.then(value => {
console.log(value)
// do whatever you're going to do with value
};
You can read up more [here][1] on how Promises work.

Related

Can a promise be safely 'swallowed'?

I'm given a promise and am returning it at the end of my function for other code to do more actions after me. A kind of middleware, if you will.
return apiCallPromise;
Lets say for some reason I wish to stop those actions from happening and "swallow" a particular promise. For example by doing the following:
if (promiseShouldBeStopped) return new Promise((resolve) => {})
return apiCallPromise;
This correctly returns a promise, however it never resolves. And so the 'promise chain' has been stopped dead in its tracks.
This seems like an anti-pattern to me as it the promise is left pending forever. Are there any bad effects of this that I should be aware of, or is this a fine technique for "filtering" promises?
Attempt to answer my own question
Does this cause memory issues?
Future code doesn't know that this promise has been filtered out, and so fails to do any "catch" or "finally" cleanup code.
In my case this is not relevant, and I want this code to take care of those errors so that the future code doesn't have to deal with them. (this means I can guarantee that onFulfilled gives the api response, and onRejected only gives an error that is actually unexpected)

Get value of resolved Promise in sync

If we know that a Promise is definitely resolved, how can we access the value and if we can't, why not?
let a = Promise.resolve(123);
console.log(a.value); // ???
The following does not work- it prints "First, Last, 123"
console.log("First");
Promise.resolve(123).then(console.log);
console.log("Last");
I'm asking how to get the value of an already resolved Promise synchronously and if that's not possible, why not?
No, it is not possible to do this. This is by design.
The Promise A+ specification is meant to be used as a simple, consistent way to deal with asynchronous operations. One of the constraints is that passing a new callback on to then() on an already resolved promise will always execute on a later tick in the event loop, so things are consistent.
Adding a secondary way to inspect promise results would not have been impossible. It would probably have been quite easy to do so, but there's at least 2 problems with adding this to the specification:
If you're looking to build a specification, you want it to be as simple as possible. The specification itself actually only defines the then() function.
By adding this feature, you're opening the door to hordes of developers getting even more confused about something that's already hard to grok.
Promises and asynchronous operations are hard for people to understand. I see questions here daily about promises and not 'getting' it. If non-async way to access promise results would be added to the default promise, I'd imagine that this would be an even larger amount. It's good to try and enforce 'the right way' of doing things.
However, this decision is not simply made for you. You're not stuck there. You can very easily build your own version of a promise that has this feature, and still works with existing promises. As long as your object has a then() function that behaves according to Promises/A+ you can do with the rest of the object whatever you want.
Promises are always asynchronous in JS.
If you're confident that promise is going to resolve then you can access it with .then method.
a.then(function(value) {
console.log("First");
console.log(value);
console.log("Last");
// expected output: 123
});
Variable a will lookalike below if it is console.log
Promise {<resolved>: 123}
__proto__: Promise
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: 123
For error handling, you can error block as mentioned in MDN docs.
Promise.resolve(123).then(function(value) {
console.log(value);
}
Take a look on this

Explore promise value in Debug Console

While debugging node process in vscode, I can write arbitrary expression to be evaluated in the Debug Console. But I don't know how to get value if I write expression that returns Promise. It would be handy for example to explore what is in database calling the model function that returns promise.
I tried
Format.all(context.engine).then(formats => console.log(formats))
But still getting only Promise object back and not the value to be resolved.

How to access JSON Object.$$state.value?

Warning: I'm going to sound like I have no idea what I'm talking about here, because I kind of don't. I'm in the process of self-learning Javascript and AngularJS through a lot of trial and error coding.
I have some javascript code (hesitant to copy here because it's a mess) that returns an Object with the following structure:
What I want to save to a variable is the object corresponding to Object.$$state.value in the picture. This object has username, hash and salt, which are what I care about. I don't know what all the other stuff like $$state are or how they got there.
However, if I do this (let's call the main Object "whatIHave"):
var whatIWant = whatIHave.$$state.value;
this does not work. whatIWant is null.
Does anyone recognize what's going on here? What is $$state, how did it get there, and how can I extract the value I want?
So that is a promise. You need to do something like:
whatIHave.then(function(whatIWant) {
// Work here
});
I highly recommend you to research what a promise is (like this link)
If you're curious enough, about what is that $$state and what is that value, I will explain a bit:
The promises have a $$state and there angular saves all the callback functions you want to call in a pending array (all those function you registered with .then like I explained before).
It also have the status: resolved (1) and rejected (2)
Finally, when you resolve or reject the promise, the value you pass when doing that, is saved in value.
You're trying to cheat in here, because when you try to access that value, it could be not there yet (that is what async is all about).
So the idea is learning the basic of promises, learning how to work with them and then use your whatIHave correctly.

AngulaJS UI-router retry promise

I am using ui-router in my angular project. My question is: What's the best practice to retry and handle correctly a promise inside a resolve?
Right now I am simulating a disconnection or timeout, when that happens the promise is rejected(with a 404), which leaves my application in an inconsistent state. I can't find the best way to retry going to that state when the server is back up, right now nothing happens because the promise was already rejected.
PS. from ui-router wiki, not sure if I couldn't find my answer there, this is the closest thing, which I guess that Ed forgot about it: https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-lazy-load-states
UPDATE(4/30 3:02pm):
While creating the plunkr example, i realized that the problem is that I'm using a service to return the promise object, then that's why the promise stays as rejected.
UPDATE(5/01 11:30AM)
SOLUTION
After playing with the plunkr last night I realized that I need to check the state of the promise, so I found this which is not too useful. By the way, I am using a service because I only need to resolve that promise once, is just retrieving a catalog from the server side that won't change for the rest of the session. So, just if you are curious, my solution will involve some kind of factory of promises(http gets), so if the promise of the service hasn't been resolved I can create a new one and go to the correct state.
Well, the direct answer is, you don't. Promises are only resolved or rejected once, and a failed resolve fails the transition. If you want to recover the transition itself, intercept $stateChangeError (or use the error callback of the transition), examine the promise rejection, and attempt to recover and re-initiate the transition. You may want to add some fail-safe code to ensure you don't do this repeatedly.

Categories

Resources