Arhn - архитектура программирования

nodejs зацикливается с асинхронной функцией внутри

У меня проблема, когда for(var x=1; x < 6; x++) вызывается, потому что слишком быстро axios.get() является асинхронным, но я понятия не имею, как с этим бороться, чтобы решение не было слишком сложным.

const axios = require("axios");
const cheerio = require("cheerio");

function imdbGetData(id) {
  var title, show, $;
  var arr = [];
  var airdates = [];
  show = {
    seasons: []
  };

  axios.get(`http://www.imdb.com/title/${id}/`).then((body) => {
    $ = cheerio.load(body.data);
    title = $("div h1").text()
  });
  for(var x=1; x < 6; x++) {
    console.log(x); // Will count too 1,2,3,4,5,6
    url = `http://www.imdb.com/title/${id}/episodes?season=${x}`
    axios.get(url).then((body) => {
      $ = cheerio.load(body.data);
      console.log(x);// 6, 6, 6, 6
      $("div .info .airdate").each(function(index, item) {
        var airdate = String($(this).text());
        airdates.push(airdate.trim());
      });


      $(".info strong a").each(function(i, item){
          var airdate = airdates[i];

          var epsiode_name = $(this).text()
          if (epsiode_name && !epsiode_name.includes("#"))
            arr.push({epsiode_name, airdate});
      });
      show.seasons.push(arr);
      arr = []
      // console.log(show.seasons);
    });
    setTimeout(() => {console.log(show.seasons)}, 10000) // ghetto
  }
}

// season = {
//   seasons: [[ {epsiode_name} ], [{Epsiode name}]]
// }

imdbGetData("tt2193021");


Ответы:


1

Вы также можете использовать async/await (в более новых версиях Node.js), чтобы сделать код немного легче для чтения, я также внес несколько небольших изменений для обновления прогресса.

const axios = require("axios");
const cheerio = require("cheerio");

async function imdbGetData(id) {

    var title, show, $;
    var arr = [];
    var airdates = [];
    show = {
    seasons: []
    };

    console.log('Getting from ' + `http://www.imdb.com/title/${id}/`);
    let body = await axios.get(`http://www.imdb.com/title/${id}/`);

    $ = cheerio.load(body.data);
    title = $("div h1").text()

    for(var x=1; x < 6; x++) {
        console.log('Getting season: ' + x); // Will count too 1,2,3,4,5,6
        url = `http://www.imdb.com/title/${id}/episodes?season=${x}`
        let body = await axios.get(url);
        $ = cheerio.load(body.data);
        $("div .info .airdate").each(function(index, item) {
            var airdate = String($(this).text());
            airdates.push(airdate.trim());
        });

        $(".info strong a").each(function(i, item){
            var airdate = airdates[i];

            var epsiode_name = $(this).text()
            if (epsiode_name && !epsiode_name.includes("#"))
                arr.push({epsiode_name, airdate});
        });
        show.seasons.push(arr);
        arr = []

    }

    console.log("Result: ", show.seasons);
}

imdbGetData("tt2193021");
15.02.2018
  • Хотя этот ответ верен для самой последней версии узла, он не может осветить причину проблемы, с которой столкнулся OP, которая заключается в том, что вы не можете обрабатывать асинхронные вызовы, как если бы они были синхронными, потому что вы не можете предсказать, когда завершится асинхронный вызов. . Я думаю, что следующий ответ, хотя и неполный, обеспечивает основу для лучшего решения, поскольку показывает, как можно управлять несколькими параллельными операциями с помощью Promise.all(). 16.02.2018

  • 2

    Вы можете создать и отправить все промисы в массив, а затем использовать Promise.all(arrayOfPromises). Таким образом, вы сохраните свою асинхронную цепочку и сможете легко обрабатывать результаты, очень похожие на обычную одиночную асинхронную операцию:

    var promises = [];
    for (var x = 1; x < 6; x++) {
      url = `http://www.imdb.com/title/${id}/episodes?season=${x}`
      promises.push(axios.get(url));
    }
    
    Promise.all(promises)
      .then(body => {
        // all results of promises will be in 'body' parameter
      })
      .catch(err => console.error(err));
    
    15.02.2018
  • Это хорошо, если у вас есть 30 URL-адресов, но для всего EPG это зальет веб-сервер. 17.02.2018
  • @MichałCzapracki, залить сервер? Как? Таким образом, вы делаете только то количество запросов, которое вам действительно нужно, и включаете в массив промисов. Я имею в виду, какая разница для сервера, когда я отправляю новый запрос в каждом then блоке и когда я отправляю их все одновременно? 17.02.2018
  • Вы открываете много соединений и пытаетесь получить доступ к большому количеству данных одновременно - это идет к серверу, который обычно имеет ограниченный пул потоков, или даже если нет, он будет использовать для этого много ресурсов. Вы должны контролировать количество ожидающих запросов, чтобы выполнять 10-20 одновременных вызовов. Promise.all этого не решит, потому что ваши запросы уже сделаны до вызова Promise.all. 18.02.2018

  • 3

    Вы можете просто использовать ES6 let вместо var , ваш код будет таким:

    for(let i=0; i<length; i++){
       asyncCall(function(){
        console.log(i);// will print 0,1,2,3,...
        });
    }
    

    Пожалуйста, ознакомьтесь с этой статьей https://codeburst.io/asynchronous-code-inside-an-array-loop-c5d704006c99

    21.06.2019
    Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..