Why do my promises stay in the pending state and how do I fix it?
var foundPeopleA = findPeopleA().then(function(result) {
var res = []
result.map(function(el) {
res.push(getProfileXML(el.sid));
});
return res
});
var foundPeopleB = findPeopleB().then(function(result) {
var res = []
result.map(function(el) {
res.push(getProfileXML(el.sid));
});
return res
})
return Promise.all([findPeopleA, findPeopleB]).then(function(results) {
console.log(results) //[ [ Promise { <pending> }, Promise { <pending> } ], [ Promise { <pending> }, Promise { <pending> } ] ]
})
However if i change the body of the 2 functions above into
var res
result.map(function(el) {
res = getProfileXML(el.sid);
});
return res
they won't be pending and I'll get the result.
Arrays are not promises. If you return an array of promises, then gets an array of promises - just like if you return any other non-promise value. Only if you return a promise, the promise will get executed before then. Your foundPeopleA and foundPeopleB each construct an array of promises; you need to concatenate those arrays and pass them to Promise.all or equivalent in order to get them executed.
The problem is that you are handling the promises fulfillment on each of them individually by using then, and all handles the fulfillment of multiple promises by passing it an array of unresolved promises. It builds a new promise with the results of all of them together. Just use:
Promise.all([findPeopleA(), findPeopleB()])
.then(function(responses) ...
Try assigning your Array to the result of the mapping.
var foundPeopleA = findPeopleA().then(function(result) {
var res = []
res = result.map(function(el) {
return getProfileXML(el.sid);
});
return res
});
Or, perhaps you can resolve the promise?
var foundPeopleA = findPeopleA().then(function(result) {
var res = []
res = result.map(function(el) {
return getProfileXML(el.sid);
});
resolve(res);
});
Either way, I belive you need to build your array by returning values from the mapping to create the new array.
Related
I have a code which has an array of Promises
async function getResult(){
...
//resultPromise ==> it has promise in array Ex.[Promise { <pending> }, Promise { <pending> }]
let finalResult = await resultPromise.map((result) => {
//result has each promise from promise array
result.then((obj) => {
return obj.data
})
})
}
From this I want to get obj.data stored in the variable finalResult. How can I do that?
I tried below ways
return resultPromise.map((result)=>{
result.then((obj)=>{
console.log(obj.data)
return obj.data
})
})
or
resultPromise.map((result)=>{
result.then((obj)=>{
console.log(obj.data)
return obj.data
})
})
I know the chaining way but, I couldn't get the correct value from it.
Use Promise.all.
async function getResult(){
...
let finalResult = (await Promise.all(resultPromise)).map((obj) => obj.data);
...
}
I have this function that I need to move from AngularJs to VueJs and it has me stumped! Any help would be appreciated :)
items = {
one: {...details here...},
two: {},
}
AngularJs
var promises = [];
var deferred = $q.defer();
angular.forEach(items, function(details) {
promises.push(details.promise);
});
$q.all(promises).finally(function() {
deferred.resolve();
});
return deferred.promise;
What I have in VueJs so far
let promises = [];
for (let [name, details] of Object.entries(items)) {
promises.push(new Promise((resolve) => {resolve(details)}));
}
return Promise.all(promises);
Thank you!
There is no need for new Promise because Promise.all allows for non-promise values.
For a promise that resolves with undefined (this is what a deferred does) when all object values are settled (i.e. resolved or rejected), it's:
Promise.all(Objects.values(items).map(({ promise }) => promise))
.then(() => {}) // if it's necessary to resolve with undefined
.catch(() => {}) // if it's necessary to not reject
If all values aren't promises, there is no need for Promise.all at all.
I have a problem with async/await and some Promises.
I have this code. It starts here:
let valid = await LoadRouter.load(body);
console.log(valid);//showing me Pending Promises
The function is:
loadGeneratingUnits(data){
let newUGArray = [];
try {
const result = data.map(async (itemGU, index) => {
const checGU = await this.checkDataGu(itemGU.nombre);
if(!checGU){
let newUG = {
generating_unit_name: itemGU.nombre,
description: (!itemGU.descripcion) ? null : itemGU.descripcion,
it_generating_unit_id: (!itemGU.it_unidad_generadora) ? 0 : itemGU.it_unidad_generadora
}
newUGArray.push(newUG);
}
})
return result;
} catch (error) {
throw new Error(error.message)
}
}
This one is where I have the problems
async checkDataGu(guName = null){
if(guName){
return await generatingUnitModel.findOne({
attributes: [
'id',
'generating_unit_name',
],
where: {
generating_unit_name: guName
}
})
}
}
Any comment about the use of async/await on this code?
By making the callback to data.map() async, data.map() is now transforming the data into an array of Promises, because the return value of an async function is always a Promise. await only will wait for a Promise to resolve, not an array of them. You should use Promise.all for that:
const result = Promise.all(data.map(async (itemGU, index) => {
const checGU = await this.checkDataGu(itemGU.nombre);
if(!checGU){
let newUG = {
generating_unit_name: itemGU.nombre,
description: (!itemGU.descripcion) ? null : itemGU.descripcion,
it_generating_unit_id: (!itemGU.it_unidad_generadora) ? 0 : itemGU.it_unidad_generadora
}
newUGArray.push(newUG);
}
}))
Now result is one Promise that will resolve with an array of the values each inner Promise resolved with. Ultimately this means your upper let valid = await LoadRouter.load(body); should resolve with the array you expect.
Alright so I kinda got stuck doing nested queries with firestore because of ForEach and nested Promise returns. From all the previous posts on stackoverflow I understood quite a bit about promises and then nesting them inside ForEach. However, I couldnt find a solution where I nest promise inside forEach which then has another forEach inside it.
I do understand that I have to use Promise.all to make the root forEach wait but how to tell it to wait until the .then() also returns something?
firebase.firestore().collection("Feeds").get().then(feedsSnapshot => {
let promiseArray = [], anotherPromiseArray = [];
feedsSnapshot.forEach(function (feed) {
let promise = checkifILikedTheFeed(feed).then(like => {
return like;
}).then(like => {
let anotherPromise = firebase.firestore().collection("Feeds").doc(feed.id).collection("Likes").get()
.then(likesSnapshot => {
if(likesSnapshot.empty){
return {
// return myData
};
} else {
let countLikes = 0;
likesSnapshot.forEach(likeDoc => {
if(likeDoc.data().isLike){
countLikes++;
}
});
return {
//myData + countLikes
};
}
});
anotherPromiseArray.push(anotherPromise);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// I thought this would work, sadly doesnt.
});
promiseArray.push(promise);
});
return Promise.all([promiseArray,anotherPromiseArray]);
}).then(feeds => {
console.log(feeds);
// ^^^^^^^^^^^^^^^^^^^
// returns [[undefined],[undefined]]
dispatch({
type: 'RETRIEVE_FEEDS',
payload: feeds,
});
});
I have this code:
db.group.findOne({_id: id}).then((groupFound) => {
var membersArray = groupFound.members;
Promise.all(membersArray.map((member) => {
return db
.doneTodo
.find({'victor._id': member._id})
.then((userVictories) => {
return {
email: member.email,
victories: userVictories.length
}
});
})).then(function (result) {
console.log(result);
});
The db calls are all MongoDB/Mongoose.
The inside of the array returned from the map function is all promises.
The last call:
.then((userVictories) => {
return {
email: member.email,
victories: userVictories.length
}
})
returns a promise.
So essentially, after this call is made, what I have is:
[promise1, promise2, promise3, ... , promise x]
How are these promises concluded to change the array value to the value of promise1.then( (result))?
How are these promises concluded to change the array value to the value of promise1.then( (result))?
There's nothing special here. The promises within the array will act like any promise does - they will resolve to some value after a period of time, result in an error after some period of time, or if they were set up poorly, never resolve or produce an error.
The purpose of Promise.all is simply to wait for all of the values in the array to resolve or for one to throw an error. If they all resolve, the promise returned from Promise.all will resolve to an array of all the results. If one throws an error, it will produce that error.
Promise.all isn't doing anything to the promises, just watching them. We could create our own simple version of Promise.all like this:
function myAll(arr) {
var resolvedCount = 0;
var resultArray = [];
return new Promise(function (resolve, reject) {
if (arr.length === 0) {
resolve([]);
}
arr.forEach(function (el, i) {
// wrap el in a promise in case it's not already one
Promise.resolve(el)
.then(
function (result) {
// add result to the result array and increment the count
resultArray[i] = result;
resolvedCount += 1;
if (resolvedCount === arr.length) {
// all promises have resolved,
// so this promise can resolve itself
resolve(resultArray);
}
},
function (err) {
// a promise threw an error. reject
reject(err);
}
); // end of .then()
}); // end of .forEach()
}); // end of new Promise()
}
// test out myAll()
function log(value) { console.log(value); }
function logError(value) { log('Error caught:' + value); }
myAll([])
.then(log, logError);
myAll([1, Promise.resolve('apple'), 5, Promise.resolve(7)])
.then(log, logError);
myAll([2, 3, Promise.reject('no!')])
.then(log, logError);