完成node.js内部的循环承诺

时间:2016-12-20 19:36:00

标签: node.js for-loop foreach promise firebase-admin

我正在尝试使用.forEach在firebase对象上完成一些循环,我也在使用promises。这还没有弄清楚我的计划方式。我的基本问题是,在promise链本身完成之后,我的promise中的循环完成得很好。这是我的功能:

var queue = new Queue(productUpdateQueue, function(data, progress, resolve, reject) {

    var incomingUpdateData = data;
    var receiptID = incomingUpdateData.receiptID;
    var userID = incomingUpdateData.userID;
    var oldProductID = incomingUpdateData.oldProductID;
    var newProductID = incomingUpdateData.newProductID;
    var newReceipt = incomingUpdateData.newReceipt;

    var postID = "";

    var updateObject = {};

    updateObject['usersPrivate/'+userID+'/receipts/'+receiptID+'/items/'+oldProductID] = null;
    updateObject['usersPrivate/'+userID+'/receipts/'+receiptID+'/items/'+newProductID] = newReceipt;

    clicks.child('VigLink').orderByChild('item').equalTo(oldProductID).once('value', function(cuidSnapshot) {
        return cuidSnapshot.forEach(function(cuidSnapshot) {
            var cuid = cuidSnapshot.key;
            updateObject['clicks/VigLink/'+cuid+'/item'] = newProductID;
            console.log('one');
            progress(20);
        });
    }).then(function() {
        return userReceiptMetrics.child(userID).child('receipts').child(receiptID).child('items').child(oldProductID).once('value', function(oldSnapshot) {
            var data = oldSnapshot.val()
            updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/items/'+oldProductID] = null
            updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/items/'+newProductID] = data
            if (data != null) {
                updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/itemIDs/'+newProductID] = now
                updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/itemIDs/'+oldProductID] = null
            };
            console.log('two');
            progress(40);
        });
    }).then(function() {
        return userReceiptMetrics.child(userID).child('shops').child(oldProductID).once('value', function(oldSnapshot) {
            var data = oldSnapshot.val()
            updateObject['userReceiptMetrics/'+userID+'/shops/'+oldProductID] = null;
            updateObject['userReceiptMetrics/'+userID+'/shops/'+newProductID] = data;
            if (data != null) {
                updateObject['userReceiptMetrics/'+userID+'/shopIDs/'+newProductID] = now;
                updateObject['userReceiptMetrics/'+userID+'/shopIDs/'+oldProductID] = null;
            };
            console.log('three');
            progress(60);
        });
    }).then(function() {
        posts.once('value', function(postSnapshot) {
            // use Promise.all and Array#map to wait for all these queries to finish

            var allPosts = postSnapshot.val()
            var postKeys = Object.keys(allPosts)

            return Promise.all(postKeys.map(function(postKey) {
                var postID = postKey;

                return posts.child(postID).child('items').child(oldProductID).once('value', function(itemSnapshot) {

                    return itemSnapshot.forEach(function(itemSnapshot) {
                        var itemData = itemSnapshot.val()
                        console.log('post snapshot'+ itemData);
                        updateObject['posts/'+postID+'/items/'+oldProductID] = null
                        updateObject['posts/'+postID+'/items/'+newProductID] = itemData
                    });
                });
            }));
        });
    }).then(function() {
        // Move to next item
        return console.log('hey look here'+updateObject['posts/'+postID+'/items/'+newProductID]);
        return firebaseRoot.update(updateObject, function(error) {
            if (error) {
                console.log("Error updating data:", error);
                reject()
            } else {
                progress(100);
                // resolve();
                console.log('four');
            }
        });
    }).then(function() {
        // Move to next item
        return console.log('second one'+updateObject['posts/'+postID+'/items/'+newProductID]);
        return firebaseRoot.update(updateObject, function(error) {
            if (error) {
                console.log("Error updating data:", error);
                reject()
            } else {
                progress(100);
                // resolve();
                console.log('four');
            }
        });
    });

    // Finish the task asynchronously
    setTimeout(function() {
        reject();
    }, 10000);
});

这是输出:

one
two
three
hey look hereundefined
second oneundefined
post snapshot[object Object]
post snapshot[object Object]
post snapshot[object Object]
post snapshot[object Object]
post snapshot[object Object]
post snapshot[object Object]
post snapshot[object Object]
post snapshot[object Object]

我想我可能会错误地使用承诺,但我不知道。

1 个答案:

答案 0 :(得分:0)

我发现我应该使用Promise.all()来等待我的forEach循环完成。这是我用来解决问题的代码,享受:

var queue = new Queue(productUpdateQueue, function(data, progress, resolve, reject) {

    var incomingUpdateData = data;
    var receiptID = incomingUpdateData.receiptID;
    var userID = incomingUpdateData.userID;
    var oldProductID = incomingUpdateData.oldProductID;
    var newProductID = incomingUpdateData.newProductID;
    var newReceipt = incomingUpdateData.newReceipt;

    var postID = "-KZOO0UII67uOmYo6DJh";

    var postKeys = [];

    var updateObject = {};

    updateObject['usersPrivate/'+userID+'/receipts/'+receiptID+'/items/'+oldProductID] = null;
    updateObject['usersPrivate/'+userID+'/receipts/'+receiptID+'/items/'+newProductID] = newReceipt;

    return clicks.child('VigLink').orderByChild('item').equalTo(oldProductID).once('value', function(cuidSnapshot) {
        return cuidSnapshot.forEach(function(cuidSnapshot) {
            var cuid = cuidSnapshot.key;
            updateObject['clicks/VigLink/'+cuid+'/item'] = newProductID;
            progress(10);
        });
    }).then(function() {
        return userReceiptMetrics.child(userID).child('receipts').child(receiptID).child('items').child(oldProductID).once('value', function(oldSnapshot) {
            var data = oldSnapshot.val()
            updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/items/'+oldProductID] = null
            updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/items/'+newProductID] = data
            if (data != null) {
                updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/itemIDs/'+newProductID] = now
                updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/itemIDs/'+oldProductID] = null
            };
            progress(25);
        });
    }).then(function() {
        return userReceiptMetrics.child(userID).child('shops').child(oldProductID).once('value', function(oldSnapshot) {
            var data = oldSnapshot.val()
            updateObject['userReceiptMetrics/'+userID+'/shops/'+oldProductID] = null;
            updateObject['userReceiptMetrics/'+userID+'/shops/'+newProductID] = data;
            if (data != null) {
                updateObject['userReceiptMetrics/'+userID+'/shopIDs/'+newProductID] = now;
                updateObject['userReceiptMetrics/'+userID+'/shopIDs/'+oldProductID] = null;
            };
            progress(40);
        });
    }).then(function() {
        progress(55);
        return posts.orderByChild('receipt').equalTo(receiptID).once('value');
    }).then(function(postSnapshot) {
        return postSnapshot.forEach(function(post) {
            progress(70);
            postKeys.push(post.key)
        });
    }).then(function() {
        return Promise.all(postKeys.map(function(postKey) {
            return posts.child(postKey).child('items').child(oldProductID).once('value', function(itemSnapshot) {
                var itemData = itemSnapshot.val()
                updateObject['posts/'+postKey+'/items/'+oldProductID] = null;
                updateObject['posts/'+postKey+'/items/'+newProductID] = itemData;
            });
        })).then(function(results) {
            progress(85);
            return results;
        });
    }).then(function() {
        return firebaseRoot.update(updateObject, function(error) {
            if (error) {
                console.log("Error updating data:", error);
                reject()
            } else {
                progress(100);
                resolve();
            }
        });
    });

    // Finish the task asynchronously
    setTimeout(function() {
        reject();
    }, 10000);
});