Короткая версия:
Объедините все 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 циклов.