Can I confirm if my understanding of the code below is roughly correct?
function fetchDog(){
k = fetch("https://dog.ceo/api/breeds/image/random")
console.log(k);
};
fetchDog();
k is displayed on the console as a Promise object. Because the console is live, this promise does resolve to fulfilled.
function fetchDog(){
fetch("https://dog.ceo/api/breeds/image/random")
.then(response => console.log(response))
};
fetchDog();
The fulfilled promise resolves to a response object. It ceases being a Promise object because it's resolved to something else entirely.
No.
A promise will always be a promise. It's state may change from pending to resolved, but nothing about promises causes variables referencing them to mutate to reference their resolved value.
To get the resolved value you need to use then() or await.
First of all, a resolved promise is still a promise. The value doesn't magically get overwritten. What .then is doing is it's essentially adding a function as a listener and saying, once the promise resolves, run this function with the value that the promise is resolved with. So, inside the function, response is not the promise, but the contents of the promise. The actual promise still lives on. Consider this code:
const x = Promise.resolve("hello"); // generate a promise that immediately resolves to "hello"
x.then(v => console.log(v));
x.then(v => console.log(v));
// "hello" is logged twice
Related
Source: developer.mozilla.org
new Promise((resolveOuter) => {
resolveOuter(
new Promise((resolveInner) => {
setTimeout(resolveInner, 1000);
})
);
});
This promise is already resolved at the time when it's created
(because the resolveOuter is called synchronously), but it is resolved
with another promise, and therefore won't be fulfilled until 1 second
later, when the inner promise fulfills.
My Inference: Even a pending promise counts as a resolved promise therefore the statement
this promise is already resolved at the times it's created
My Question: How does resolveOuter being called synchronously affect the resolution of a promise? Is it the mere fact that the newly created promise needs to exist at a certain state? I know I'm missing something deeper here. I'm very new to promises, can somebody please elaborate?
The outer promise calls resolveOuter() immediately (synchronously), BUT you're calling resolve() with another promise that is still pending. That means it will not yet be resolved until the child promise is also resolved.
So, the outer promise is immediately in the pending state, but it's watching the inner promise. The inner promise is also immediately in the pending state since it's been created, but resolve() has not yet been called.
Then, the setTimeout() fires and that resolves the inner promise. The outer promise is watching the inner promise (with the equivalent of .then()) and when it sees that the inner promise resolves, it can then resolve itself.
How does resolveOuter being called synchronously affect the resolution of a promise?
If you were calling resolveOuter() with a static value, then the outer promise would immediately go to the fulfilled state. But, you called resolveOuter(somePendingPromise) so that outer promise is still pending and is waiting for the inner promise to fulfill/reject.
If a promise is created this way:
myPromise = new Promise(function(resolve, reject) {});
Can this promise be ever resolved by any way? Obviously, the executor is not resolving it in this case, so can the promise be ever resolved?
I think if it is jQuery, it can be resolved by deferred.resolve() so that the related promise deferred.promise() is resolved.
No, the promise can only be resolved or rejected by the resolve and reject functions, respectively.
If these functions aren't called nor exposed, the promise will remain in pending state forever.
That's also a security level, as it helps you ensure the promise you wait for will resolve to the value you expect and when you expect; and allows you to safely return an internal promise, as it is (without any hazards or leaking secrets).
To make a promise, that relies on another promise you don't have control over, but can be resolved (or rejected) manually, regardless of the original, you can use the Promise.race() function:
//The original promise that may pend forever
const original = new Promise(()=>{})
//Controller promise, whose resolver is exposed (or contains the logic needed for "manual" resolution)
let resolve
const controller = new Promise(rs=>{resolve=rs})
//The promise you wait for (and can be resolved or rejected either by `original` or `controller`)
const mixed = Promise.race([original,controller])
mixed.then(console.log)
setTimeout(()=>resolve('Resolved'), 2000)
Assign the resolve function to a variable outside the scope of the promise
I have a pretty silly problem. Consider the following:
vm.feed = getFeed().then(function(data) {return data;});
getFeed() returns a $q deferred promise (I am on angular) that resolves successfully.
My goal is to set vm.feed equal to the data value returned by the successful callback. As it is right now, the code simply assigns vm.feed equal to the $promise object returned by getFeed().
I know I could simply do: vm.feed = data inside the resolved function but I want to understand why this code does not work as it is.
PD: the promise resolves correctly and even after it has been resolved vm.feed keeps being equal to the Promise, and not data. I copy the console.log of vm.feed after +10 seconds have elapsed:
Promise {$$state: Object} $$state: Objectstatus:1 value: Object
That value property inside the Promise object contains the actual solution of the promise that I want to assign to vm.feed (e.i. data).
thank you!
This could be updated to ES6 with arrow functions and look like:
getFeed().then(data => (vm.feed = data));
If you wish to use the async function, you could also do like that:
async function myFunction(){
vm.feed = await getFeed();
// do whatever you need with vm.feed below
}
Edit: added parenthesis to be eslint correct (as commented by Max Waterman)
You are going to get whatever then() returns. But since you are reading this, the following may help you:
Your statement does nothing more than ask the interpreter to assign the value returned from then() to the vm.feed variable. then() returns you a Promise (as you can see here: https://github.com/angular/angular.js/blob/ce77c25b067b7b74d90de23bfb4aac6a27abb9d1/src/ng/q.js#L288). You could picture this by seeing that the Promise (a simple object) is being pulled out of the function and getting assigned to vm.feed. This happens as soon as the interpreter executes that line.
Since your successful callback does not run when you call then() but only when your promise gets resolved (at a later time, asynchronously) it would be impossible for then() to return its value for the caller. This is the default way Javascript works. This was the exact reason Promises were introduced, so you could ask the interpreter to push the value to you, in the form of a callback.
Though on a future version that is being worked on for JavaScript (ES2016) a couple keywords will be introduced to work pretty much as you are expecting right now. The good news is you can start writing code like this today through transpilation from ES2016 to the current widely supported version (ES5).
A nice introduction to the topic is available at: https://www.youtube.com/watch?v=lil4YCCXRYc
To use it right now you can transpile your code through Babel: https://babeljs.io/docs/usage/experimental/ (by running with --stage 1).
You can also see some examples here: https://github.com/lukehoban/ecmascript-asyncawait.
The then() method returns a Promise. It takes two arguments, both are callback functions for the success and failure cases of the Promise. the promise object itself doesn't give you the resolved data directly, the interface of this object only provides the data via callbacks supplied. So, you have to do this like this:
getFeed().then(function(data) { vm.feed = data;});
The then() function returns the promise with a resolved value of the previous then() callback, allowing you the pass the value to subsequent callbacks:
promiseB = promiseA.then(function(result) {
return result + 1;
});
// promiseB will be resolved immediately after promiseA is resolved
// and its value will be the result of promiseA incremented by 1
You could provide your function with the object and its attribute. Next, do what you need to do inside the function. Finally, assign the value returned in the promise to the right place in your object. Here's an example:
let myFunction = function (vm, feed) {
getFeed().then( data => {
vm[feed] = data
})
}
myFunction(vm, "feed")
You can also write a self-invoking function if you want.
This is one "trick" you can do since your out of an async function so can't use await keywork
Do what you want to do with vm.feed inside a setTimeout
vm.feed = getFeed().then(function(data) {return data;});
setTimeout(() => {
// do you stuf here
// after the time you promise will be revolved or rejected
// if you need some of the values in here immediately out of settimeout
// might occur an error if promise wore not yet resolved or rejected
console.log("vm.feed",vm.feed);
}, 100);
I have an object whose value comes from an AJAX request. I'm converting it to a promise and am encountering some behaviour with promises that I don't expect. I have an example here that exhibits the same behaviour, but I'm substituting Q.all() for my AJAX request.
(Thing = function(){
var promise;
var refresh = function() {
promise = Q.all(["a", "b"]);
};
var fetch = function(i) {
return promise.then(function(promiseVal){
return promiseVal[i];
});
};
refresh();
return {
"fetch": fetch,
"refresh": refresh,
"promise": promise
};
}());
Thing is executed on load and runs "refresh" to populate itself initially. The point of the "fetch" function is that my async request (Q.all in this case) returns a promise for an array, but what I really want is a promise for elements in the array (e.g. a promise for "a" or a promise for "b"). So I'm expecting Thing.fetch(1) to return a promise for "b".
Thing.fetch(1) does return a promise, but if I do Thing.fetch(1).valueOf() it returns a promise, not "b" as I was expecting. If I do:
Thing.fetch(1).then(function(foo){
console.log(foo);
});
it will print "b" on the console.
If I do Thing.promise.valueOf() it returns the array, so the promise is resolved when I call "fetch".
So my question is why doesn't valueOf() return a value when I call it on the promise returned by "fetch"?
It seems your promise is not resolved yet.
It's not well documented, but scattered over the wiki pages I found:
The valueOf call returns the promise itself by default.
The valueOf method is useful for providing information about the
promise in the same turn of the event loop. For example, resolved
promises return their resolution value and rejections return an object
that is recognized by isRejected.
If the promise is fulfilled, promise.valueOf() returns the fulfilled
value. If the promise is or has forwarded to a deferred promise, it
returns most recently deferred promise. For rejected promises,
promise.valueOf() returns a sentinel object with
{rejectedPromise: true, reason: {}}
When you're doing Thing.fetch(1).then(console.log); it will of course print "b" on the console - that's the resolve value which is passed to the callback. But notice that it will invoke the log function in the future!
Because the value of the promise is an array.
The value of the function passed to "then" will be some value.
Your fetch method is not really returning a promise, it is resolving a promise.
Let's say I'm building a typical RSS-reader. I'm parsing several feeds and write all their episodes to DB:
const processEpisode = (episode)=>
fetchMetadata(episode)
.then(parseMetadata)
.then(writeToDb)
const processFeed = (feed)=>
fetchEpisodes(feed) // returns [Episode]
.map(processEpisode, { concurrency: 3 })
// main
getFeeds() // returns [Feed]
.map(processFeed, { concurrency: 3 })
.catch(err=> console.log(err))
We get all the feeds
For each feed emit processFeed()
For each episode emit processEpisode() from processFeed()
However, if fetchMetadata(episode) for some episode for some feed throws a rejection, all the chain is broken and immediately falls into global .catch(err=> console.log(err)).
In normal situation we need to do something with unprocessed episode, but the least should be processed normally. One solution is to wrap processEpisode() in an outer Promise and handle in-place.
const processEpisode = (episode)=>
new Promise((resolve, reject)=> {
fetchMetadata(episode)
.then(parseMetadata)
.then(writeToDb)
.then((result)=> resolve(result))
.catch((err)=> {
// something bad happened
// process and error, but resolve a fullfilled Promise!
resolve(true)
})
})
However, I suppose it's an obvious anti-pattern. And if after processEpisode() there is another element in higher level Promise chain, it will fail 'cause processEpisode will resolve true instead of real result.
Is there an elegant way to solve such problems? I've looking through finally statement in Bluebird, but I'm not sure it's the best way.
Thank you!
Just put a .catch() handler directly on processFeed() so you can process the rejection locally and turn it into a resolved promise which will allow everything else to continue:
// main
getFeeds() // returns [Feed]
.map(function(item, index, length) {
return processFeed(item, index, length).catch(function(reason) {
// do whatever you want to here, this will "handle" the rejection
// and turn it into a resolved promise
// whatever you return here will become the resolved value
});
}, { concurrency: 3 })
.catch(err=> console.log(err))
Note: You don't need the extra wrapping promise. Adding a .catch() handler and returning a normal value from the .catch() handler will turn the rejected promise into a resolved promise as the rejection is considered "handled" at this point. Whatever value you return from the .catch() handler becomes the resolved value of the parent promise.
A .catch() handler will only keep the promise rejected if it returns a rejected promise or throws.