【问题标题】:pass value from promise to promise with Node.js使用 Node.js 将值从一个承诺传递到另一个承诺
【发布时间】:2016-12-21 07:11:19
【问题描述】:

我正在尝试传递一个我使用 firebase 逐个构建的对象。如果有更好的方法来逐步构造对象,我真的不需要沿着承诺链传递对象。这是我的代码:

    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() {
        return 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) {

                    itemSnapshot.forEach(function(itemSnapshot) {
                        var itemData = itemSnapshot.val()
                        console.log('post snapshot'+ itemSnapshot);
                        updateObject['posts/'+postID+'/items/'+oldProductID] = null
                        updateObject['posts/'+postID+'/items/'+newProductID] = itemData
                    });
                });
            })).then(function(results) {
                // put progress update in .then, and return the results 
                progress(75);
                return results;
            });
        });
    }).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');
            }
        });
    });

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

输出是:

one
two
three
hey look hereundefined
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]

非常感谢任何和所有帮助。

【问题讨论】:

  • 能否检查执行是否真的进入了为userReceiptMetrics.child(userID).child('receipts').child(receiptID).child('items')上的value事件注册的回调。子(oldProductID)变量?
  • 正如我现在所看到的,它永远不会退出第一个承诺部分。我看到进度设置为 12,然后服务器崩溃。
  • 那么是什么让你说它永远不会退出第一个承诺?报告的错误似乎指向试图影响 updateObject['userReceiptMetrics/'+userID+'/shops/'+oldProductID] 的说明,这些说明在链条的下游
  • 是的,这就是我不明白的。如果我在第一个承诺之外的任何地方放置一个 console.log() 语句,它就不会被调用。此外,我正在观察它在工作时(在它崩溃之前)将数据放到我的 firebase 上,并且它似乎只到达了在崩溃之前将进度设置为 12 的部分。
  • 真的,我在想可能return updateObject; 没有将对象传递给下一个promise,所以updateObject 是未定义的。我错了吗?

标签: javascript node.js promise firebase-realtime-database


【解决方案1】:

你需要改变你的.then from(现在在问题中改变了,但代码最初有这个)

}).then(function(updateObject) {

}).then(function() {

这样你的代码总是更新new Queue回调中声明的updateObject

另外,每个 then 中的第一行都需要添加一个 return

所以,而不是

userReceiptMetrics.child(userID).child('receipts').child(receiptID).child('items').child(oldProductID).once('value', function(oldSnapshot) {

你有

return userReceiptMetrics.child(userID).child('receipts').child(receiptID).child('items').child(oldProductID).once('value', function(oldSnapshot) {

进度调用需要放在 .once 回调的末尾

总的来说,代码应该看起来像(删除了大部分正确的代码,希望这是可以理解的

var queue = new Queue(productUpdateQueue, function(data, progress, resolve, reject) {
    // removed for brevity
    var updateObject = {};
    // removed for brevity
    clicks.child('VigLink').orderByChild('item').equalTo(oldProductID).once('value', function(cuidSnapshot) {
        // removed for brevity
        progress(12);
    }).then(function() {
        return userReceiptMetrics.child(userID).child('receipts').child(receiptID).child('items').child(oldProductID).once('value', function(oldSnapshot) {
            // removed for brevity
            progress(25);
        });
    }).then(function() {
        return userReceiptMetrics.child(userID).child('shops').child(oldProductID).once('value', function(oldSnapshot) {
            // removed for brevity
            progress(50);
        });
    }).then(function() {
        return posts.orderByChild('items').equalTo(oldProductID).once('value', function(postSnapshot) {
            // use Promise.all and Array#map to wait for all these queries to finish
            return Promise.all(postSnapshot.map(function(postSnapshot) {
                var postID = postSnapshot.key;

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

                    itemSnapshot.forEach(function(itemSnapshot) {
                        var itemData = itemSnapshot.val()

                        updateObject['posts/'+postID+'/items/'+oldProductID] = null
                        updateObject['posts/'+postID+'/items/'+newProductID] = itemData
                    });
                });
            })).then(function(results) {
                // put progress update in .then, and return the results 
                progress(75);
                return results;
            });
        });
    }).then(function() {
        // Move to next item
        console.log(updateObject);
        // removed for brevity
    });

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

【讨论】:

  • 感谢 Jaromanda X 十亿!我很确定他们的承诺是按顺序发生的,并且在我在 Firebase 上设置对象之前我做错了其他事情。您的帮助非常有帮助,因此我在本周六授予您“g”奖。你是正式的g。
  • 好的。所以看起来这是可行的,除了一个问题。我使用的两个循环都在整个承诺链结束后完成。不能在 Promise 中使用循环吗?
  • 抱歉,没有注意到 forEach 循环也使用异步代码 - 让我修改答案
  • 我已经用(希望的)正确代码为在 forEach 中使用 asynch 的那一部分编辑了答案 - 它使用 Promise.all 和 Array#map 来等待所有内部查询解决跨度>
  • 它告诉我.map is not a function
【解决方案2】:

所以我终于想出了如何做到这一点。我在逐步传递对象时遇到问题,但我真正想做的是逐步创建对象。所以我在 Promise 链之外创建了对象,并一步一步地构建它。这里的主要障碍之一是让我的循环完成,然后继续执行链中的下一个承诺。为此,我使用Promise.all() 来返回结果。

它起作用了,现在我对 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 = "-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);
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-06
    • 1970-01-01
    • 2015-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多