Как выполнить код после 2-х вложенных циклов в узле - PullRequest
0 голосов
/ 05 января 2020

Я пытаюсь найти наименьшее значение («лучший результат») в 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 }));
        }
    });
});

1 Ответ

1 голос
/ 06 января 2020

Короткая версия:

Объедините все 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() никогда не используется, потому что функция находится в блоке .then() без return, за которым следует .then(), который ничего не делает с несуществующим значением.

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

Однако, так как вы переназначаете bestScore в обратном вызове getConnectionAccounts и это глобальный у вас будет побочный эффект. Поэтому, когда приведенный выше код запускается, result будет неопределенным и bestScore неизвестным в тот момент, когда вы переназначаете его в обратном вызове. Это означает, что все Promises из Promise.all() должны преобразовываться в мусор. (какое-то значение)

Как для вашего случая:

Первым делом следует получить переназначение, if (bestScore > accountScore) bestScore = accountScore;, где-то в конце цепочки. Сделайте условным, чтобы все Обещания должны были разрешить, где Promise.all() вступает в игру.

Таким образом, в отличие от комментария, вы можете вставлять асинхронные вызовы. НО вы должны вернуть Promise изнутри .then(). Это означает, что либо обратный вызов должен разрешить возвращенный 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 циклов.

...