JavaScript promise not working with resolve()

2019-05-25 04:37发布

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?

3条回答
可以哭但决不认输i
2楼-- · 2019-05-25 04:45

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); });
    });
});
查看更多
一纸荒年 Trace。
3楼-- · 2019-05-25 04:49

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);
    }
});
查看更多
唯我独甜
4楼-- · 2019-05-25 04:51
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)
    })
})
查看更多
登录 后发表回答