I was interested in "await" behavior, so I ran this code
console.log(await Promise.resolve(Promise.resolve(Promise.resolve("hahaha"))));
in my browser console, the result is correct "hahaha". It seems there is a hidden loop in "await" till no Promise remains. I didn't find explanation from MDN. Anybody knows why? Thanks.
From the MDN documentation:
This function flattens nested layers of promise-like objects (e.g. a promise that fulfills to a promise that fulfills to something) into a single layer — a promise that fulfills to a non-thenable value.
"hahaha" is the non-thenable value that it fullfills to.
Related
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)
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
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.
I'm having trouble controlling execution flow. This is a follow-on to node.js, bluebird, poor control of execution path and node.js table search fails with promises in use. Judging by console.log print-outs, my recursive routine works great, except that the first call to resolve() (a signal to the nth recursive call) gives the green light to follow-on code that shouldn't get that green light until the first call to the recursive routine calls resolve(). It turns out the first call to the recursive routine delivers the answer I want reported, but by the time it reports it, the follow-on code is no longer listening for it and is running blissfully along with an "undefined" answer. Bad.
My code is much to long to share here. I tried to write a small model of the problem, but haven't found the combination of factors to replicate the behavior.
Sound familiar? How do you keep proper control over Promises releasing follow-on code on time?
I thought maybe the first call to the routine could start an array passed into a Promise.all and later calls would add another entry to that array. I haven't tried it. Crazy?
Without seeing your actual code, we can't answer specifically.
Sound familiar? How do you keep proper control over Promises releasing
follow-on code on time?
The answer is always to not resolve the first promise in the chain until you're ready for things to execute and to structure your promise chain so that dependent things don't get executed until the things they are waiting on have been properly resolved. If something is executing too soon, then you're either calling something too soon or your promise structure is not correct. Without seeing your actual code, we cannot know for sure.
A common mistake is this:
someAsyncOperation().then(someOtherAync()).then(...)
which should be:
someAsyncOperation().then(someOtherAync).then(...)
where you should pass a reference to the next async function rather than calling it immediately and passing its return value.
I thought maybe the first call to the routine could start an array
passed into a Promise.all and later calls would add another entry to
that array. I haven't tried it. Crazy?
You cannot pass an array to Promise.all() and then add things to the array later - that is not a supported capability of Promise.all(). You can chain subsequent things onto the results of Promise.all() or do another Promise.all() that includes the promise from the previous Promise.all() and some more promises.
var someArrayOfPromises = [...];
var pAll = Promise.all(someArrayOfPromises);
var someMorePromises = [...]
someMorePromises.push(pAll);
Promise.all(someMorePromoises).then(...)
I have seen code that looks like this:
var defer = Q.defer();
// do something, here's the callback
if (err) {
defer.reject({err: err})
}
defer.resolve({success: data});
// close callback
return defer.promise;
If a promise is first rejected, and then resolved, it appears that the "rejection" remains.
When I first saw this pattern, I was inclined to suggest to wrap the resolve inside an else, but since it works as is, is this an acceptable pattern?
Could there ever be a problem with rejecting and then resolving a promise?
It appears that if you resolve and then reject, the resolution remains. So whichever happens first, is what "sticks"?
So whichever happens first, is what "sticks"?
Yes, exactly. The state of a promise is immutable once it is settled (either fullfilled or rejected). So no, there can't be a problem occurring here, the promise is "locked" as rejected if the rejection happens first.
However, think about if a single else doesn't actually improve your code quality. Less code lines don't necessarily improve code readability! I'd say it would, because it's much easier to quickly understand what happens if you see an if/else. What if someone else has to look at your code, and they also at first don't know that promises are immutable after settling?
Chapter 3 of "You Don't Know JS (async & performance)" is an excellent resource to more fully grasp promises. And so is the Promises A+ specification, which Q conforms to. The latter is more of an "objective source of truth", but it's harder to read (well, it's a spec).