2017-01-23 4 views
0

Сегодня я перехожу на следующий этап своего веб-сканера!Асинхронный двойной обратный вызов в петле NodeJS

Я уже зацикливаюсь на массиве url с async, и я бы снова зациклился на этом обратном вызове и дождался его exectution перед перезагрузкой.

Я не могу понять, как использовать два обратных вызова.

Это мой код:

var getWebData = function(url) { 
    var data = []; 
    async.eachSeries(url, function(urlSingle, cb) { 
     request(urlSingle, function(err, resp, body) { 
     if (!err) { 
      var $ = cheerio.load(body); 
      var categoriesURL = []; 
      $('.ombre_menu li').each(function(i, element) { 
       $(this).find('.nav_sous-menu_bloc li a').each(function(i, element) { 
       categoriesURL.push('https://blabla' + $(this).attr('href')); 
       }) 

       // I WANT TO LOOP on the categoriesURL array HERE 

       var jsObject = { name : "", description : "", price: "", categorie: "", liter: "", kilo: "", pricePer: "", quantity: "", capacity: "", promotion: "", scrapingDate : "", url: "" }; 
       data.push(jsObject); 
      }) 
     } 
     cb(); 
     }) 
    }, function() { 
    // this will rum when loop is done 
    var json = JSON.stringify(data); 
    fs.writeFile('output.json', JSON.stringify(json, null, 4), function(err) { 
     console.log('File successfully written!'); 
    }); 
    }); 
} 

getWebData(url); 
app.listen('8080'); 

Кто-нибудь знает, как я могу сделать?

Thanks

ответ

0

Сделано несколько изменений в коде:

  1. Используется .mapSeries вместо .eachSeries. Таким образом, вы можете получить данные из функции iterator в том же порядке, что и входной массив. Значит, вы получите [4,9] для ввода [2,3] в квадратную функцию, никогда [9,4]
  2. Разбитый код на функции, чтобы каждая функция выполняла одну конкретную задачу
  3. Перемещенные категорииURL обработка петли 1
  4. Возвращение рано. Это улучшает читаемость кода. if (err) return callback(err);

function getWebData(url) { 

    // Using .mapSeries in place of .eachSeries as you seem to want to get data from iterator function 
    async.mapSeries(url, processUrl, function(err, results) { 
    // this will rum when loop is done 
    var json = JSON.stringify(results); 
    fs.writeFile('output.json', JSON.stringify(json, null, 4), function(err) { 
     console.error('Error', err); 
     console.log('File successfully written!'); 
    }); 
    }); 
} 

function processUrl(url, callback) { 
    request(url, function(err, resp, body) { 
    if (err) // Return simple cases early; Improves code readability 
     return callback(err); // or return callback(); -- if you don't want to send error upwards 

    var $ = cheerio.load(body); 
    var categoriesURL = []; 

    $('.ombre_menu li') 
     .each(function(i, element) { // loop 1 
     $(this) 
      .find('.nav_sous-menu_bloc li a') 
      .each(function(i, element) { // loop 2 
      categoriesURL.push('https://blablablac' + $(this) 
       .attr('href')); 
      }) // loop 2 end 

     }) // loop 1 end 
    // I WANT TO LOOP ON THE categoriesURL ARRAY HERE 
    // Using .mapSeries in place of .eachSeries for same above reason 
    async.mapSeries(categoriesURL, processCategoryUrl, function(err, results) { 
     if (err) 
     return callback(err); 
     // This function is called after process array categoriesURL 

     // Do what you want here then call callback provided to this method 
     return callback(null, results); 
    }) 
    }) 
} 

function processCategoryUrl(categoryUrl, callback) { 
    // Just process categoryUrl here and call callback with error or results 
    return callback(); 
} 

getWebData(url); 
app.listen('8080'); 
+0

Большое спасибо @Sangharsh за ваш ответ, но я не знаю, как использовать этот код ... – rastafalow

+0

У вас есть какие-то особые сомнения? – Sangharsh

+0

Я попробовал код, заменил urlSingle по url (потому что у меня был ReferenceError: urlSingle не определен), и похоже, что у меня бесконечный цикл. @Sangharsh – rastafalow

0

Вы можете использовать вложенные eachSeries. Как это:

var getWebData = function(url) { 
    var data = []; 
    async.eachSeries(url, function(urlSingle, cb) { 
     request(urlSingle, function(err, resp, body) { 
     if (!err) { 
      var $ = cheerio.load(body); 
      var categoriesURL = []; 
      $('.ombre_menu li').each(function(i, element) { 
       $(this).find('.nav_sous-menu_bloc li a').each(function(i, element) { 
       categoriesURL.push('https://blablablac' + $(this).attr('href')); 
       }) 
       async.eachSeries(caturl, function(categoriesURL, cb2) { 
         //Do whatever you want to do here 
         cb2(); 
       }, function() { 
       //You can apply if and else for err an according to that you can set your callback responce here 
       cb(); 
       }; 
      }) 
     } 
     }) 
    }, function() { 
    // this will rum when loop is done 
    var json = JSON.stringify(data); 
    fs.writeFile('output.json', JSON.stringify(json, null, 4), function(err) { 
     console.log('File successfully written!'); 
    }); 
    }); 
} 

getWebData(url); 
app.listen('8080'); 
+0

Спасибо Панкай за ваш ответ, я не хочу иметь другую функцию после моего второго цикла. Может быть, я могу взять второй и потушить cb()? – rastafalow