Reputation: 2315
I was having some problem with promise in JavaScript. So what I am trying to do is I wanted to retrieve from firebase, then store all the result returned into array. After that I will perform some sorting on the array. Here is my code:
let promise = new Promise((resolve, reject) => {
var query = firebase.database().ref('');
query.once( 'value', data => {
data.forEach(subtypeSnapshot => {
var itemData = ;
var query = firebase.database().ref('').child(itemKey);
query.once( 'value', data => {
var itemDetail = ;
datasetarr.push();
});
});
resolve(datasetarr);
});
});
With this set of code, from the first console.log
inside the promise, I managed to get these in my console:
With these, it means there is nothing wrong with my firebase retrieval. Afterwhich, I wanted to store each of them into array and this is the part:
datasetarr.push({type: subtype, quantity: quantity});
After done everything and I resolved the promise, when promise is done, I then print out the items in array. However, nothing is printed out at the for loop inside .then()
. Any ideas?
Upvotes: 3
Views: 2139
Reputation: 92440
var query = firebase.database().ref('receiptItemIDsByCategory').child(category);
query.once('value')
.then((data) => {
promises =[]
data.forEach( subtypeSnapshot => {
var itemData = subtypeSnapshot.val();
var itemKey = subtypeSnapshot.key;
var query = firebase.database().ref('receiptItems').child(itemKey);
p = query.once( 'value', data => {
var itemDetail = data.val();
var subtype = itemDetail.type;
var quantity = itemDetail.quantity;
console.log('inside promise ' + subtype + ' ' + quantity);
});
promises.push(p)
})
return promises
})
.then ((arrayofpromises) => {
Promise.all(arrayofpromises)
.then((results)=>{
console.log(results)
})
})
Upvotes: 1
Reputation: 6527
As already mentioned: Your Promise is resolved too early.
You can use Promise.all to wait for all promises to resolve before resolving the wrapping Promise. I put together a simple example, however, because of the lack of a firebase database, I just use functions returning Promises: https://jsfiddle.net/57b0gkLt/
According to the firebase documentation, query.once('value')
returns a Promise, so this should work.
EDIT: Like this
var datasetarr = [];
let promiseItemDataList = new Promise((resolve, reject) => {
var query = firebase.database().ref('receiptItemIDsByCategory').child(category);
query.once( 'value', data => {
var promises = []; // NEW LINE
data.forEach(subtypeSnapshot => {
var itemData = subtypeSnapshot.val();
var itemKey = subtypeSnapshot.key;
var query = firebase.database().ref('receiptItems').child(itemKey);
var promise = query.once('value'); // NEW LINE
promises.push(promise); // NEW LINE
promise.then(data => { // .then instead of a callback
var itemDetail = data.val();
var subtype = itemDetail.type;
var quantity = itemDetail.quantity;
console.log('inside promise ' + subtype + ' ' + quantity);
datasetarr.push({type: subtype, quantity: quantity});
});
});
Promise.all(promises).then(() => resolve(datasetarr)); // NEW LINE
});
});
promiseItemDataList.then((arr) => {
for(var i = 0; i < arr.length; i++){
console.log('outside promise ' + arr[i].type + ' ' + arr[i].quantity);
}
});
Upvotes: 1
Reputation: 19268
Your first async
call for retrieving the initial set of data was handled correctly but not the subsequent ones invoked by the .forEach
loop.
query.once( 'value', data => {
var itemDetail = data.val();
var subtype = itemDetail.type;
var quantity = itemDetail.quantity;
console.log('inside promise ' + subtype + ' ' + quantity);
datasetarr.push({type: subtype, quantity: quantity});
});
Trouble is you're resolving
the promise before the other async call was returned.
I'm not sure how exactly is query.once
handling callback
. It doesn't look like it is doing promises nor the traditional callback function
way.
What you could do as a work-around
is to wrap the forEach.async
calls into a Promise
object and then fire a collection of promises using Promise.all([list_of_promises])
to make sure that every single call was returned before resolving
the main promise.
Pseudo code:
var datasetarr = [];
let promiseItemDataList = new Promise((resolve, reject) => {
var query = firebase.database().ref('receiptItemIDsByCategory').child(category);
query.once( 'value', data => {
// Collect a list of promises for the sub item async calls
var get_data_promises = [];
data.forEach(subtypeSnapshot => {
get_data_promises.push(new Promise(function(resolve) {
var itemData = subtypeSnapshot.val();
var itemKey = subtypeSnapshot.key;
var query = firebase.database().ref('receiptItems').child(itemKey);
query.once( 'value', data => {
var itemDetail = data.val();
var subtype = itemDetail.type;
var quantity = itemDetail.quantity;
console.log('inside promise ' + subtype + ' ' + quantity);
datasetarr.push({type: subtype, quantity: quantity});
resolve("Done");
});
}))
// Fire them all - Once done resolve the main promise.
Promise.all(get_data_promises).done(function() { resolve(datasetarr); });
});
});
Upvotes: 1