对于循环,循环中的总增量为零,但随后打印时返回0

时间:2019-02-05 13:33:30

标签: javascript loops promise axios

我正在创建一个Alexa应用程序,该应用程序充当股票的投资组合经理。我有一个函数,该函数首先检索所有股票和属于用户的股票数量。对于每种股票,我必须使用axios查询API以获取股票的价值,这意味着axios get语句嵌套在forEach循环内。然后,我有一个totalPrice变量,该变量使用股票的总价格递增;将价格乘以拥有的股票数量x即可得出

在forEach循环结束时,我要打印totalPrice,这将是投资组合的整个价值

当我在request语句中打印出totalPrice时,它会正确添加以前的总股票价格,但是如果我在forEach循环之后打印totalPrice,则会显示0

var grandTotal = 0;
data.Items.forEach(function(element,index,array) {  
   var stock = element.Stock;
   var number = element.Number;
   var url = `www.api.com/${stock}`;

   const getDataValues = async url => {
     try {
      const response = await axios.get(url);
      const data = response.data;
      var Price = data.PRICE;
      return Price;
    } catch (error) {
      console.log(error);
    }
  };

 let promiseObject = getDataValues(url);
 promiseObject.then(function(result) {
     var totalPriceofStocks = result * amount;
     grandTotal += totalPriceOfStocks;
     console.log(`{grandTotal}`);        // This bit accumulates correctly
 });
});
console.log(`The grand total is: ${grandTotal}`);

令我困惑的是,尽管数据是异步的,但我认为使用.then会一直等到检索到数据为止。似乎是这样,因为在forEach循环中打印总计时可以正常工作。有趣的是,在控制台中,“总计为:0”首先打印。

2 个答案:

答案 0 :(得分:1)

最后的console.log打印0,因为它在您的诺言开始之后(并且尚未完成)立即执行。

为了等到所有承诺都完成,您可以:

  1. 将承诺存储在列表中
  2. 使用Promise.all,它将承诺列表作为参数,并在所有承诺均已解决时(在您的情况下,当所有axios请求完成时)进行解析。

我添加了修改后的代码示例,以演示如何执行此操作。由于我没有您的数据,因此我无法对其进行测试,但希望它能起作用。

const promises = []

const getDataValues = async url => {
  try {
    const response = await axios.get(url);
    const data = response.data;
    var Price = data.PRICE;
    return Price;
  } catch (error) {
    console.log(error);
  }
};

var grandTotal = 0;
data.Items.forEach(function(element,index,array) {  
  var stock = element.Stock;
  var number = element.Number;
  var url = `www.api.com/${stock}`;

  let promiseObject = getDataValues(url);
  promiseObject.then(function(result) {
    var totalPriceofStocks = result * amount;
    grandTotal += totalPriceOfStocks;
    console.log(`${grandTotal}`);        // This bit accumulates correctly
    return totalPriceOfStocks
  });
  promises.push(promiseObject)
});

Promise.all(promises)
  .then(function (resultValues) {
    console.log(`The grand total is: ${grandTotal}`);
    let resultSum = 0;
    resultValues.forEach(function (value) {
      resultSum += value;
    })
    console.log(`This is also the total: ${resultSum}`);
  })

还请注意,我已向您的promise对象添加了返回值。我这样做是为了显示一种积累总计而不是依赖于全局值的替代方法。 其背后的逻辑是,当Promise返回一个值时,该值可用于传递给'then'链接函数的函数。在这种情况下,当我们使用Promise.all时,Promise.all将一个Promise返回值的列表传递给它的'then'函数。因此,我们可以将returnValues参数的元素加在一起以计算总计。

答案 1 :(得分:0)

使用for..of循环,而不是forEach,await应该在其中按预期方式工作

for (const element of data.Items) {
   var stock = element.Stock;
   var number = element.Number;
   var url = `www.api.com/${stock}`;

   const getDataValues = async url => {
     try {
      const response = await axios.get(url);
      const data = response.data;
      var Price = data.PRICE;
      return Price;
    } catch (error) {
      console.log(error);
    }
  };

 const result = await getDataValues(url);
 var totalPriceofStocks = result * amount;
 grandTotal += totalPriceOfStocks;
 console.log(`{grandTotal}`);
}