【问题标题】:How to execute code after 2 nested loops in node如何在节点中的 2 个嵌套循环后执行代码
【发布时间】:2020-01-05 18:36:19
【问题描述】:

我试图在 2 个嵌套循环中找到最低值(“最佳分数”),然后在循环完成后保存结果。以下代码似乎在循环之前而不是之后执行最终保存。

var bestScore = 300;
SaltEdge.getCustomerConnections(customerId, function(res1) {
    Promise.all(res1.json.data.map(function(connection) {
        return Promise.resolve()
            .then(function() {

                SaltEdge.getConnectionAccounts(connection.id, function(res2) {
                    if (res2.json.data) {
                        return Promise.all(res2.json.data.map(function(account) {

                            SaltEdge.get3MonthsIncome(connection.id, account.id, function(threeMonthsIncome) {
                                console.log('threeMonthsIncome', threeMonthsIncome);
                                var accountScore = SaltEdge.threeMonthsIncomeToScore(threeMonthsIncome);
                                console.log('account score', accountScore);
                                if (bestScore > accountScore) bestScore = accountScore;

                                console.log('best score', bestScore);
                                return bestScore;
                            });
                        }));
                    }
                });

            })
            .then(function(result) {
                return bestScore;
            });
    })
    ).then(function(res) {
        console.log("i'm here" + bestScore, res);
        if (bestScore < 300) {
            console.log('--update score', bestScore);
            Borrower.update(borrowerId, {salt_edge_score: bestScore}, function() {
                done(new Response(200,{ updated: true }));
            });
            resolve(bestScore);
        } else {
            done(new Response(200,{ updated: true }));
        }
    });
});

【问题讨论】:

  • 您不能在承诺链的中间插入像SaltEdge.getConnectionAccounts(connection.id, function(res2) {...}); 这样的普通回调异步函数。当你这样做时,promise 链将不会在它的回调中等待它或任何东西。您需要在承诺链中承诺所有异步操作,以便正确链接它们。

标签: node.js asynchronous promise async-await


【解决方案1】:

短版:

将所有Promises 聚合到一个数组中,并将Promise.all() 与该数组一起使用。或者为内部循环的Promise.all() 设置一个数组,并使用另一个Promise.all() 等待它们到所有resolve。结果[[...],[...],[...]]的数据结构。

为什么会失败:

所以你的电话:

SaltEdge.getConnectionAccounts(connection.id, function(res2) {
    if (res2.json.data) {
    // is never used
    return Promise.all(res2.json.data.map(function(account) {

什么都没有,因为 Promise.all() 永远不会被消耗,因为该函数位于没有 return.then() 块中,然后是 .then(),它对不存在的值不执行任何操作。

.then(function(result) {
    return bestScore;
});

但是,由于您在 getConnectionAccounts 的回调中重新分配 bestScore 并且这是一个全局变量,因此您将产生副作用。因此,当上面的代码运行时,result 将是未定义的,bestScore 是未知的,因为您在回调中重新分配了它。这意味着来自Promise.all() 的所有Promises 都应该解析为垃圾。 (一些价值)

如何处理您的情况:

首要任务应该是重新分配if (bestScore &gt; accountScore) bestScore = accountScore;,在链条末端的某个位置。条件是所有 Promise 都必须解决 Promise.all() 发挥作用的地方。

因此与注释相反,您可以插入异步调用。但是您必须从.then() 中返回Promise。这意味着要么回调必须解析返回的Promise,要么被调用的函数必须返回自己的Promise

那么SaltEdge.getConnectionAccounts() 是否返回Promise?如果是,只需return 函数调用。如果不使用这样的东西:

return new Promise(function (resolve) {
    SaltEdge.get3MonthsIncome(connection.id, account.id, function (threeMonthsIncome) {
        console.log('threeMonthsIncome', threeMonthsIncome);
        var accountScore = SaltEdge.threeMonthsIncomeToScore(threeMonthsIncome);
             console.log('account score', accountScore);
             if (bestScore > accountScore) bestScore = accountScore;

             console.log('best score', bestScore);
             resolve(bestScore);
     });
})

回顾一下:我们现在对每个分数都有一个承诺。我们可以一次将所有这些Promises 提供给Promise.all()。只需从您的内部map() 中返回一个数组,然后将flat() 附加到您的外部map()

Promise.all(
    res1.json.data.map(
        function (connection) {

            // will return an array of promises
            return SaltEdge.getConnectionAccounts(connection.id, function (res2) {
                if (res2.json.data) {
                    return res2.json.data.map(function (account) {
                        // for better readability return added
                        return new Promise(function (resolve) {
                            SaltEdge.get3MonthsIncome(connection.id, account.id, function (threeMonthsIncome) {
                                console.log('threeMonthsIncome', threeMonthsIncome);
                                var accountScore = SaltEdge.threeMonthsIncomeToScore(threeMonthsIncome);
                                console.log('account score', accountScore);

                                // move this assignment
                                if (bestScore > accountScore) bestScore = accountScore;

                                console.log('best score', bestScore);
                                // resolving the promise inside the callback
                                resolve(bestScore);
                            });
                        })
                    })
                }
            });
        }
    // flat should get rid of the nested arrays
    ).flat()
) // use .then() for what to do with the array

Promise.all() 将解析为所有调用的所有值的数组。那是您在 2 次循环后执行代码的时候。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-05
    • 2019-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-06
    相关资源
    最近更新 更多