简体   繁体   中英

JavaScript promise not working with resolve()

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?

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);
    }
});

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); });
    });
});
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)
    })
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM