2014-03-29 63 views
0

所以我一直在困惑这个,只是无法弄清楚如何解决这个问题。Javascript中的范围/闭包 - 如何更新全局变量?

我有一个嵌套的函数,循环遍历一个对象数组,并刮擦每个对象的URL的社交链接。

之后,我想通过包括{ social: [array of social urls] }来更新每个对象。但是,我得到了{ social: [] }

我试过把contacts[i].social = results放在这个的其他部分,但是我得到一个“找不到对象”的错误。

帮助,将不胜感激......

var contacts = [ 
    { title: 'Healthy breakfast: Quick, flexible options to grab at home - Mayo Clinic', 
    url: 'http://www.mayoclinic.org/healthy-living/nutrition-and-healthy-eating/in-depth/food-and-nutrition/art-20048294' }, 
    { title: 'Healthy Breakfast Ideas from Dr. Weil\'s Facebook Readers', 
    url: 'http://www.drweil.com/drw/u/ART03113/Healthy-Breakfast-Ideas-from-Facebook-Readers.html' }, 
    { title: '8 Healthy Breakfast Ideas - Prevention.com', 
    url: 'http://www.prevention.com/food/healthy-eating-tips/8-healthy-breakfast-ideas' }, 
    { title: 'Quick & Easy Healthy Breakfast Ideas! - YouTube', 
    url: 'http://www.youtube.com/watch?v=mD4YSD8LDiQ' }, 
    { title: 'The Best Foods to Eat for Breakfast - Health.com', 
    url: 'http://www.health.com/health/gallery/0,,20676415,00.html' }, 
    { title: 'Healthy Breakfast Recipes - Secrets To Cooking Healthier - YouTube', 
    url: 'http://www.youtube.com/watch?v=7jH0xe1XKxI' }, 
    { title: 'Healthy Breakfast Ideas You Can Make the Night Before - FitSugar', 
    url: 'http://www.fitsugar.com/Healthy-Breakfast-Ideas-You-Can-Make-Night-Before-20048633' }, 
    { title: '10 Easy, 5-Minute Breakfast Ideas - Diet and ... - Everyday Health', 
    url: 'http://www.everydayhealth.com/diet-and-nutrition-pictures/easy-5-minute-breakfast-ideas.aspx' }, 
    { title: 'Healthy Breakfast Ideas for Kids | Parenting - Parenting.com', 
    url: 'http://www.parenting.com/gallery/healthy-breakfast-ideas-kids' }, 
    { title: 'Fruits & Veggies More Matters : Healthy Breakfast Ideas : Health ...', 
    url: 'http://www.fruitsandveggiesmorematters.org/healthy-breakfast-ideas' } 
]; 

scraper(contacts); 

// loops through contacts database and scrapes requested information 
function scraper(contacts) { 

    // Adds the domain of each contact 
    for(var i=0;i<contacts.length;i++){ 
     contacts[i].domain = contacts[i].url.split(/\//, 3).join().replace(/,/g, '/'); 
    }; 

    // 
    for(var i=0;i<contacts.length;i++){ 
     var homepage = contacts[i].domain; 

     var results = []; 

     function socialScrape(homepage) { 
      request(homepage, function(err, resp, html) { 
       var $ = cheerio.load(html); 

       if(!err && resp.statusCode == 200) {  
        $('a').each(function(i, el){ 
         var a = $(el).attr('href'); 
         for(var key in socialURLS){ 
          if(socialURLS[key].test(a) && results.indexOf(a) < 0){ 
           results.push(a); 
          } 
         } 

        }); 
       } else { console.log(err); } 
      }) 
     } 
     contacts[i].social = results; 
     socialScrape(homepage); 
    } 

console.log(contacts); 

} 

回答

1

你的第一个问题是,您的通话request是异步的,还没有被时间contacts[i].social = results执行返回,所以contacts[i].results是越来越指派一个空数组,[]。 (这个问题的变化每天都在SO上多次发布,对此问题的一个很好的解释可以在这里找到:How do I return the response from an asynchronous call?)解决这个问题并不简单,只需将contacts[i].social = results;移动到request调用成功处理程序中,因为值i将在之前更改处理程序被调用。

你的第二个问题是results定义的socialScrape函数定义之外 - 因此不是每request呼叫项目数组,你有一个阵列的所有request结果。为您解决范围的问题,最好的办法是用封闭,我们可以通过删除调用socialScrape(homepage);,使socialScrape自调用函数实现:

(function socialScrape(homepage) { 
    var results = []; 
    var index = i; 
    request(homepage, function(err, resp, html) { 
     /* do error and status check stuff and build our results array */ 
     contacts[index].social = results; 
    }); 
}(homepage)); 

注意我们是如何捕捉i内的电流值关闭并将其分配给index。这将使我们能够在交付结果时通过索引获得正确的联系方式。