2016-12-06 91 views
-2

我創建使用Express和請求刮刀。 將一個URL數組傳遞給請求,然後通過for循環迭代該請求。一旦所有的數據被解析並且所有的數據都被解析了,回調函數就會調用res.send。回報倍數承諾從循環

我想這個轉換成承諾,但我相信在for循環我使用不會允許我。如果循環導致問題,是否有另一種方法我可以編碼並獲得相同的結果?

回調方法

function scrape(callback){ 
     for(var i = 0; i < urls.length; i++){ 
      request(urls[i], function(error, response, html){ 
       if(!error && response.statusCode == 200){ 
        // LOAD Cherio (jQuery) on the webpage 
        var $ = cheerio.load(html); 
        try{ 
         var name = $(".name").text(); 
         var mpn = $(".specs.block").contents().get(6).nodeValue.trim(); 
         var jsontemp = {"MPN": "", "Name": "", "PriceList": {}}; 

         jsontemp.MPN = mpn; 
         jsontemp.Name = name; 
         // Traverse the DOM to get tr tags and extract info 

         $(".wide-table tbody tr").each(function (i, row) { 
          var $row = $(row), 
           merchant = $row. attr("class").trim(), 
           total = $row.children(".total").text(); 
           jsontemp.PriceList[merchant] = merchant; 
           jsontemp.PriceList[merchant] = total; 
         }); 
        } 
        catch(err){ 
         console.log('Error occured during data scraping:'); 
        } 

         list.push(jsontemp); 
       } 
       else{ 
        console.log(error); 
       } 
      count++; 
      callback(); 
      }); 
     } 
    } 
}); 

scrape(() => { 
    console.log(count); 
    if(count == urls.length){res.send(list)} 
}); 

承諾履行嘗試

var urls = [ 
    "http://test.com/", 
    "http://test.com/2" 
]; 
var list = []; 
var count = 0; 

scrape().then((data) => { 
      list.push(data) 
      if(count == urls.length){res.send(list)} 
     }) 
     .catch(error => console.log(error)) 


function scrape(){ 
    for(var i = 0; i < urls.length; i++){ 
     return new Promise(function (resolve, reject) { 

      request(urls[i], function(error, response, html){ 

      if(!error && response.statusCode == 200){ 
       var $ = cheerio.load(html); 
       try{ 
        var name  = $(".name").text(); 
        var mpn   = $(".specs.block").contents().get(6).nodeValue.trim(); 
        var jsontemp = {"MPN": "", "Name": "", "PriceList": {}}; 

        jsontemp.MPN = mpn; 
        jsontemp.Name = name; 

        // TRAVERSING DOM FOR DATA // 
        $(".wide-table tbody tr").each(function (i, row) { 
         var $row = $(row), 
          merchant = $row. attr("class").trim(), 
          total = $row.children(".total").text(); 
          jsontemp.PriceList[merchant] = merchant; 
          jsontemp.PriceList[merchant] = total; 
        }); 
       } 
       catch(err){ 
        console.log('Error occured during data scraping:'); 
       } 

        resolve(jsontemp); 
      } 
      else{ 
       console.log(error); 
       return reject(error); 
      } 
     count++; 
     }); 
    } 
} 

回答

1

您需要將這些承諾存儲在一個列表中,然後調用Promise.all得到一個承諾的一切:

function scrape() { 
    var promises = []; // array of promises 
    for(var i = 0; i < urls.length; i++) { 
    var url = urls[i]; 
    var promise = new Promise(function(resolve, reject) { 
     // ... 
    }; 

    // add to array 
    promises.push(promise); 
    } 

    // return a single promise with an array of the results 
    // by using Promise.all 
    return Promise.all(promises); 
} 

此外,不要在函數內部使用var時使用循環內循環變量(如i)。相反,你應該聲明的承諾回調函數外url變量,或與新的let更換var