我在 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,然后减少它的输出。

【讨论】:

forEachmap 都是同步的,但是您将 mapPromise.all 一起使用是对的 谢谢,我刚刚检查过了——我一直生活在 forEach 是异步的错误幻想中!

以上是关于我在 forEach 中更新的变量,返回到它们的原始值 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法从不同的 foreach 中获取值?

C# 使用IEnumerable,yield 返回结果,同时使用foreach时,在循环内修改变量的值无效

执行异步forEach循环后重新定义全局变量[重复]

无法通过 ForEach 按钮更新 @State 变量(Int Counter)?

如何使用 SheetView 函数调用更新 ContentView 中的变量?

mongodb用变量更新数组