Почему не работает await в данном случае?

222
07 марта 2019, 05:20

друзья. Недавно начал изучать Ноду, в качестве обучающего задания придумал написать асинхронный многопоточный парсер с ограничением кол-ва одновременных загрузок. В связи с этим вопрос: Почему данный код в первом случае выполняется правильно (т.е. асинхронно, результаты выдаются после прихода всех данных с апи), а во втором случае, с ограничением числа загрузок - в ответ возвращается массив промисов?

Вот рабочий пример:

const axios = require('axios');
//It works
async function go2() {
  try {
    console.time('1st');
    const urls = [
            {
                'url': 'https://randomuser.me/api',
                'method': 'get'
            },
            {
                'url': 'https://uinames.com/api',
                'method': 'get'
            }];
    var promises = await urls.map(async function (currentValue, index,     array) {
        return axios(currentValue);
    });
    // await all three promises to come back and destructure the result     into their own variables
    var array = await Promise.all(promises).catch(function(err) {
        console.log(err.message); // some coding error in handling happened
      });;
    const results=array.map(function (currentValue, index, array) {
        return currentValue.status;
    });
    console.log(results);
    console.timeEnd('1st');
        return results;
  } catch (e) {
    console.error(e); // 
  }
}
go2();

Вот нерабочий пример:

async function go3() {
  try {
    console.time('1st');
    const MAX_SIMULTANEOUS_DOWNLOADS = 2;
    const urls = [
        {
            'url': 'https://stats.nba.com/stats/teamyearbyyearstats?LeagueID=00&SeasonType=Playoffs&TeamID=1610612759&PerMode=PerGame', 
            'method':'get'
        },
        {
            'url': 'https://api.github.com/users/wesbos', 
            'method':'get'
        },
        {
            'url': 'https://randomuser.me/api', 
            'method':'get'
        },
        {
            'url': 'https://uinames.com/api', 
            'method':'get'
        }
    ];
    let subarray = []; //массив в который будет выведен результат.
    // Разбиваем массив на чанки, чтобы сразу все ссылки не грузить за один заход
    for (let i = 0; i <Math.ceil(urls.length/MAX_SIMULTANEOUS_DOWNLOADS); i++){
        subarray[i] = urls.slice((i*MAX_SIMULTANEOUS_DOWNLOADS), (i*MAX_SIMULTANEOUS_DOWNLOADS) + MAX_SIMULTANEOUS_DOWNLOADS);
    }
   //Здесь должен по идее сработать await, но нет.
    var dataFromRequest =await  subarray.map(async function (currentValue, index, array) {
        var promises = await currentValue.map(async function (currentValue1, index1, array) {
            return axios(currentValue1);
        });
        // await all three promises to come back and destructure the result into their own variables
        var responses=await Promise.all(promises).catch(function(err) {
            console.log(err.message); // some coding error in handling happened
          });
        const results=await responses.map(function (currentValue1, index1, array) {
            console.log(index1, currentValue1.data); // some coding error in handling happened
            return currentValue1.status;
        });
        return results;
    });
    console.log(dataFromRequest);
    console.timeEnd('1st');
    return dataFromRequest;
  } catch (e) {
    console.error(e); // 
  }
}
go3();

Ответ от сервера во втором случае:

[ Promise { }, Promise { } ]

Answer 1

await должен применяться к Promise.

map - возвращает массив, поэтому нет смысла перед map ставить await.

Вместо этого, нужно передать его, например, в Promise.all и уже к результату применить await.

Answer 2

Правильный ответ дал Grundy - действительно оборачивание в Promise.all помогло. На всякий случай показываю правильный вариант кода, вдруг кому пригодится:

async function go3() {
  try {
    console.time('1st');
    const MAX_SIMULTANEOUS_DOWNLOADS = 2;
    const urls = [
        {
            'url': 'https://stats.nba.com/stats/teamyearbyyearstats?LeagueID=00&SeasonType=Playoffs&TeamID=1610612759&PerMode=PerGame', 
            'method':'get'
        },
        {
            'url': 'https://api.github.com/users/wesbos', 
            'method':'get'
        },
        {
            'url': 'https://randomuser.me/api', 
            'method':'get'
        },
        {
            'url': 'https://uinames.com/api', 
            'method':'get'
        }
    ];
    let subarray = []; //массив в который будет выведен результат.
    // Разбиваем массив на чанки, чтобы сразу все ссылки не грузить за один заход
    for (let i = 0; i <Math.ceil(urls.length/MAX_SIMULTANEOUS_DOWNLOADS); i++){
        subarray[i] = urls.slice((i*MAX_SIMULTANEOUS_DOWNLOADS), (i*MAX_SIMULTANEOUS_DOWNLOADS) + MAX_SIMULTANEOUS_DOWNLOADS);
    }
    var dataFromRequest = await Promise.all(subarray.map(async function (currentValue, index, array) {
        var promises = currentValue.map(async function (currentValue1, index1, array) {
            return axios(currentValue1);
        });
        // await all three promises to come back and destructure the result into their own variables
        var responses = await Promise.all(promises).catch(function (err) {
            console.log(err.message); // some coding error in handling happened
        });
        const results = responses.map(function (currentValue1, index1, array) {
            console.log(index1, currentValue1.data); // some coding error in handling happened
            return currentValue1.status;
        });
        return results;
        })
    );
    console.log(dataFromRequest);
    console.timeEnd('1st');
    return dataFromRequest;
  } catch (e) {
    console.error(e); // 
  }
}
go3()
READ ALSO
Собрать данные из формы в data

Собрать данные из формы в data

Начинаю изучать vue, возник вопрос, как данные из input введенные пользователем записать в массив namesThatRhyme, в виде value:введенные данные , тк сейчас...

163
Как остановить таймер на сервере nodejs?

Как остановить таймер на сервере nodejs?

перепробовал уже все методы, не могу остановить таймер на сервере nodejsПробовал разные варианты и с setInterval и setTimeout

145