简体   繁体   中英

Node.js Use Promise.all For returning asynchronous call?

Currently, I am using cloud functions to query for posts. When the post is queried for, I set some updates for firebase after querying for some additional update for the post, as such:

 const getPostsForDate = admin.firestore().collection('posts').where('timeOfDeletion', '<', currentTime)
return getPostsForDate.get().then(snapshot => {
    const updates = {} 
    var counter = 0
    const batch = admin.firestore().batch()
    snapshot.forEach((doc) => {

        var key = doc.id
        admin.database().ref('/convoID/' + key).once('value', (snapshot) => {
            if (snapshot.exists()) {
                const convoIDCollection = snapshot.val()
                for (var child in convoIDCollection) {

                    console.log(child)
                    updates["conversations/" + child] = null
                    updates["messages/"+ child] = null
                    updates["convoID/"+ child] = null
                }
            }
            updates["/convoID/" + key] = null
            updates["/reveals/" + key] = null
            updates["/postDetails/" + key] = null
            const postFireStoreRef = admin.firestore().collection('posts').doc(key)
            const posterRef = admin.firestore().collection('posters').doc(key)
            batch.delete(postFireStoreRef)
            batch.delete(posterRef)
            counter++
         })

    })
    if (counter > 0) {
        console.log("at the deletion")
          return Promise.all[admin.database().ref().update(updates), batch.commit()] 
    }
    else {
        console.log("null")
        return null
    }
})

})

The problem is, however, is that the query admin.database().ref('convoID/...) is asynchronous; thus, the updates are sent to the database empty and nothing changes. Now, the solution to this is promises, except implementing the promise.all with all the other returns is not going as expected. I have tried

 var promises = []
    snapshot.forEach((doc) => {

        var key = doc.id
        promises.push(admin.database().ref('/convoID/' + key).once('value', (snapshot) => {
            if (snapshot.exists()) {
                const convoIDCollection = snapshot.val()
                for (var child in convoIDCollection) {

                    console.log(child)
                    updates["conversations/" + child] = null
                    updates["messages/"+ child] = null
                    updates["convoID/"+ child] = null
                }
            }
            updates["/convoID/" + key] = null
            updates["/reveals/" + key] = null
            updates["/postDetails/" + key] = null
            const postFireStoreRef = admin.firestore().collection('posts').doc(key)
            const posterRef = admin.firestore().collection('posters').doc(key)
            batch.delete(postFireStoreRef)
            batch.delete(posterRef)
            counter++
         })
        )
    })
promises.all(promises).then(() =>
     if (counter > 0) {
        console.log("at the deletion")
          return Promise.all[admin.database().ref().update(updates), batch.commit()] 
    }
    else {
        console.log("null")
        return null
    }
);

Except I receive the error unexpected token if , Declaration or statement expected In the end by the promises.all() Is this the correct way to wait for the asynchronous call to finish?

To wrap this question up, I'll attempt to summarize what we covered in comments:

Fix arrow function definition. Change this:

promises.all(promises).then(() => code here)

to this:

Promise.all(promises).then(() => { code here });

And, fix calling of Promise.all(). Change this:

return Promise.all[...] 

to this:

return Promise.all([...])

And, admin.database().ref().once() will return a promise, but only if you do NOT pass .once() a regular callback.

So, change this:

promises.push(admin.database().ref('/convoID/' + key).once('value', (snapshot) => { ...}));

to this:

promises.push(admin.database().ref('/convoID/' + key).once('value').then(snapshot => {...}));

And, it's a little cleaner if you change the general structure of this:

let promises = [];
snapshot.forEach((doc) => {
   promises.push(...)
});
Promise.all(promises).then(...)

to this:

Promise.all(snapshot.map(doc => {
    return admin.database().ref('/convoID/' + key).once(...).then(...);
})).then(...);

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