NodeJS не ждут окончания HTTP-вызова - PullRequest
0 голосов
/ 10 июля 2019

У меня есть массив объектов, и я перебираю массив с помощью асинхронного цикла forEach и выполняю HTTP-запрос на получение с помощью Axios.Я говорю компилятору дождаться завершения 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)

Вот вывод, который я вижу (Обратите внимание, что первый массив теоретически должен иметь «погоду» иатрибуты '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 ]

2 голосов
/ 10 июля 2019

forEach, на самом деле, не ждет ничего : вы дали ей функцию async, чтобы она могла запланировать начальный вызов для этого, и немедленно переходит к следующемуfunction , потому что ждать нечего: в качестве асинхронной функции ее возвращаемое значение - 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)
});
0 голосов
/ 10 июля 2019

вы можете использовать для:

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

foo();
0 голосов
/ 10 июля 2019

forEach на самом деле синхронно.Он принимает функцию обратного вызова в качестве параметра, которая в данном случае является вашей функцией ASYNC.Строго говоря, все коды были выполнены, но в другое время, чем вы ожидали.Никто не был пропущен.

Async / await - просто синтаксический сахар для Promise.Это означает, что каждая строка кода после «await» в вашем цикле выполняется только тогда, когда обещание разрешено.

Лучшим способом сделать это может быть обещание. Все (), как предлагали другие.

0 голосов
/ 10 июля 2019

Метод 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');


}
0 голосов
/ 10 июля 2019

Все, что вам нужно сделать, это использовать Promise.all и Array.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);
...