NodeJS等待不等待HTTP调用完成

时间:2019-07-10 03:03:23

标签: javascript node.js promise async-await

我有一个对象数组,并使用async forEach循环遍历该数组,并使用Axios发出HTTP获取请求。我告诉编译器在继续进行之前等待axios完成,但是出于某种原因,console.log(data)仍在console.log(ret)之前运行

我认为这可能是因为forEach循环在到达等待状态并继续时会被跳过,但是我不知道如何解决此问题

data.forEach(async (e, i) => {
    let req = `https://api.darksky.net/forecast/7e12d816d7818a03901fa6a72e6802f5/${e.lat},${e.log},${Math.floor(e.start_time / 1000)}?units=si`
    let ret = await axios(req)
    console.log(ret)
    data[i]['weather'] = ret.data.currently.summary
    data[i]['cloudCover'] = ret.data.currently.cloudCover
})

console.log(data)

这是我看到的输出(请注意,第一个数组理论上应该具有'weather'和'cloudCover'属性,因为它们是附加的)

[ { start_time: 1548952405372,
    end_time: 1548953096266,
    lat: 59.57644286,
    log: 20.16817143 },
  { start_time: 1548958463054,
    end_time: 1548959597889,
    lat: 59.57644286,
    log: 20.16817143 },
  { start_time: 1548964774667,
    end_time: 1548966048587,
    lat: 59.57644286,
    log: 20.16817143 } ]

{ status: 200,
  statusText: 'OK',
  headers: 
   { date: 'Wed, 10 Jul 2019 02:57:13 GMT',
     'content-type': 'application/json; charset=utf-8',
     'content-length': '10354',
     connection: 'close',
     'x-authentication-time': '705ms',
     'x-forecast-api-calls': '13',
     'cache-control': 'max-age=86400',

5 个答案:

答案 0 :(得分:2)

实际上,

forEach不会等待任何 :您已经为其提供了一个async函数,因此它可以安排为此的开始调用并立即进行到下一个函数,因为没有什么可等待的:作为异步函数,其返回值是Promise,而不是实际数据。

如果要等到所有异步功能完成,则必须使用Promise.all

async runThisStuff() {
  await Promise.all(data.map(async (e, i) => {
    let url = `...`
    let ret = await axios(url);
    console.log(ret)
    data[i]['weather'] = ret.data.currently.summary
    data[i]['cloudCover'] = ret.data.currently.cloudCover
  });

  console.log(data);
}

如果要在全局上下文中执行此操作,则无法等待Promise.all(因为您只能在await函数中使用async),并且必须使用正常的承诺then

Promise.all(
  data.map(async(...) => { ... })
).then(() => {
  console.log(data)
});

答案 1 :(得分:0)

您需要做的就是使用Promise.allArray.map。它将等待所有诺言完成。见下文。

const newData = await Promise.all(data.map(async(e, i) => {
    let req = `https://api.darksky.net/forecast/7e12d816d7818a03901fa6a72e6802f5/${e.lat},${e.log},${Math.floor(e.start_time / 1000)}?units=si`;
    let ret = await axios(req);
    console.log(ret);
    e.weather = ret.data.currently.summary;
    e.cloudCover = ret.data.currently.cloudCover;

    return e;
}));

console.log(newData);

答案 2 :(得分:0)

forEach方法进行多个函数调用而无需等待任何东西,无论这些函数内部发生了什么。

函数内部的流程受await的影响-但forEach本身不受影响。

使用for-in循环处理同步远程请求。

async function makeCalls() {

    console.log('starting');

    for (d in data) {

       let req = `https://api.darksky.net/forecast/7e12d816d7818a03901fa6a72e6802f5/${e.lat},${e.log},${Math.floor(e.start_time / 1000)}?units=si`

       let ret = await axios(req)

       console.log(ret)

       d['weather'] = ret.data.currently.summary
       d['cloudCover'] = ret.data.currently.cloudCover
    }

    console.log('ending');


}

答案 3 :(得分:0)

forEach实际上是同步的。它以回调函数为参数,在本例中为您的ASYNC函数。因此严格来说,所有代码均已执行,但执行时间与您预期的时间不同。没有一个被跳过。

异步/等待只是Promise的语法糖。这意味着循环中“等待”之后的每一行代码仅在答应的情况下执行。

可以做到这一点的更好方法。像其他人建议的那样All()。

答案 4 :(得分:0)

您可以用于以下用途:

const foo = async () => {
  const arr = [1,2,3,4,5,6];
  for (let i of arr) {
  	const response = await // async operations
  }
}

foo();