我在 forEach 中更新的变量,返回到它们的原始值 [重复]
Posted
技术标签:
【中文标题】我在 forEach 中更新的变量,返回到它们的原始值 [重复]【英文标题】:The variables I updated in my forEach, return to their original value [duplicate] 【发布时间】:2019-10-17 19:59:37 【问题描述】:我试图查询,这将获得所有的收入和提款金额和总和,但不知何故,在 forEach 循环完成并退出后,我放置在变量中的所有更新值都返回到它们的原始值。
var withdrawbalance = 0;
var totalearning = 0;
userplans.forEach((up) =>
DepositEarning.findOne(deposit: up.deposit._id)
.then(depositearning =>
withdrawbalance += parseInt(depositearning.WithdrawableBalance, 10);
);
Earning.findOne(deposit: up.deposit._id)
.then(earnings =>
totalearning += parseInt(earnings.Earning, 10);
);
)
console.log(withdrawbalance);
console.log(totalearning);
【问题讨论】:
“恢复到原来的值”——不。它只是还没有更新。 【参考方案1】:我认为原因可能是 DepositEarning.findOne() 和 Earning.findOne() 都是异步函数。这意味着它们不会立即返回值,因此您的变量在循环之后仍然相同。
【讨论】:
【参考方案2】:只是为了加我的两分钱,
正如其他答案所述,您的 foreach
循环正在使用异步代码。它正在使用一些不属于 Js 的 API。
调用被推送到调用堆栈,然后从调用堆栈中移除。因为现在工作将由 API 处理。对
的调用console.log(withdrawbalance);
console.log(totalearning);
被添加到调用堆栈中,现在的值是什么? 0 0。
API 完成工作后,会将函数添加到task queue
中,然后event loop
将检查调用堆栈是否为空。由于它现在是空的,将在调用堆栈中添加该函数。
然后运行。然后您将获得withdrawbalance and
totalearning
值的真实值。
【讨论】:
【参考方案3】:这是一种功能性方法,可以消除循环内的突变副作用。为此,您需要一个支持 Object Rest 传播的引擎:
async function calculate(userplans)
const add = (acc, n) => acc + n;
const flatten = (acc, e) => (
depositEarnings: [...acc.depositEarnings, e.depositEarnings],
earnings: [...acc.earnings, e.earnings]
);
const depositEarnings, earnings = (await Promise.all(userplans
.map(async (up) => (
depositEarnings: await DepositEarning.findOne(deposit: up.deposit._id),
earnings: await Earning.findOne(deposit: up.deposit._id)
))))
.reduce(flatten, depositEarnings: [], earnings: []);
const withdrawalBalance = depositEarnings
.map(d => parseInt(d.WithdrawableBalance, 10))
.reduce(add, 0);
const totalEarning = earnings
.map(e => parseInt(e.Earning, 10))
.reduce(add, 0);
console.log(withdrawalBalance);
console.log(totalEarning);
【讨论】:
【参考方案4】:您正在 forEach
中运行异步代码,forEach
不会等到异步代码完成,为此,您必须使用等待原语包装您的异步代码,就像这样
await Promise.all(userplans.map(async (up) =>
await DepositEarning.findOne(deposit: up.deposit._id)
.then(depositearning =>
withdrawbalance += parseInt(depositearning.WithdrawableBalance, 10);
);
await Earning.findOne(deposit: up.deposit._id)
.then(earnings =>
totalearning += parseInt(earnings.Earning, 10);
);
))
【讨论】:
【参考方案5】:forEach
是异步的。所以 console.log 在你的变异循环之前运行。您可以使用map
使其同步,但即便如此 - 您在其中也有异步调用。您将需要进一步压平它 - 可能通过在地图上执行 Promise.all,然后减少它的输出。
【讨论】:
forEach
和 map
都是同步的,但是您将 map
与 Promise.all
一起使用是对的
谢谢,我刚刚检查过了——我一直生活在 forEach 是异步的错误幻想中!以上是关于我在 forEach 中更新的变量,返回到它们的原始值 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
C# 使用IEnumerable,yield 返回结果,同时使用foreach时,在循环内修改变量的值无效
无法通过 ForEach 按钮更新 @State 变量(Int Counter)?