2017-06-13 92 views
0

如下所示,我将对象link_to_json返回到html_to_json中声明的数组allShirts中。Node.js - 如何在所有异步调用完成后返回

但是,第三行的console.dir和返回值html_to_json记录了一个未定义引用的数组。我认为这是因为console.dirreturnlink_to_json函数完成之前执行。

我该如何确保html_to_json的返回值是填充allShirts数组?

//Go to individual links and scrape relevant info 
const link_to_json = (link) => { 
    request(link, (err, res, body) => { 
     if (!error_handler(err, res, link)) { 
      const $ = cheerio.load(body); 
      const shirt_detail = $('.shirt-details').find('h1').text(); 

      const Title = shirt_detail.substr(shirt_detail.indexOf(' ') + 1); 
      const Price = shirt_detail.substr(0, shirt_detail.indexOf(' ')); 
      const ImageURL = $('.shirt-picture').find('img').attr('src'); 
      const URL = link; 

      return new Shirt(Title, Price, ImageURL, URL); 
     } else return {}; 
    }); 
} 

//Crawl through all individual links listed in Root 
const html_to_json = body => { 
    const allShirts = []; 
    const $ = cheerio.load(body); 

    $('.products').find('a').each((index, val) => { 
     allShirts.push(link_to_json(rootURL + $(val).attr('href'))); 
    }); 

    console.dir(allShirts); // <--- HERE 
    return allShirts; 
} 
+0

是请求异步方法?我会说使用诺言。 – Apidcloud

+0

我不认为'Promise.all()'防止'html_to_json'返回,它确保'html_to_json'返回一切或没有。 –

+0

是的,但你可以使用。然后 – Apidcloud

回答

2

还有几种方法可以去这之后,但我喜欢Async库这种事情。

我怎么会处理你的问题真正得到所有的URL第一,所以改变你的身体刮除这样的事情,而不是:

const shirtLinks = []; 
$('.products').find('a').each((index, val) => { 
    shirtLinks.push(rootURL + $(val).attr('href')); 
}); 

你需要你的转换功能是异步的,以及:

const linkToJSON = (link, cb) => { 
    request(link, (err, res, body) => { 
     if (!error_handler(err, res, link)) { 
      const $ = cheerio.load(body); 
      const shirt_detail = $('.shirt-details').find('h1').text(); 

      const Title = shirt_detail.substr(shirt_detail.indexOf(' ') + 1); 
      const Price = shirt_detail.substr(0, shirt_detail.indexOf(' ')); 
      const ImageURL = $('.shirt-picture').find('img').attr('src'); 
      const URL = link; 

      return cb(null, new Shirt(Title, Price, ImageURL, URL)); 
     } 
     return cb(); 
    }); 
} 

然后使用异步他们跨获取数据的异步函数映射:

async.map(shirtLinks, linkToJSON, (err, results) => { 
    console.dir(results); 
}); 
2

这就是我要做的。我发现这种方式更容易调试。

let getShirtDetailsBody = (link) => { 
 
    return new Promise((resolve, reject) => { 
 
    request(link, (err, res, body) => { 
 
     if (err) { 
 
     reject(err) 
 
     } else { 
 
     resolve(body) 
 
     } 
 
    }) 
 
    }) 
 
} 
 

 
let getShirt = (body) => { 
 
    const $ = cheerio.load(body); 
 
    const shirt_detail = $('.shirt-details').find('h1').text(); 
 

 
    const Title = shirt_detail.substr(shirt_detail.indexOf(' ') + 1) 
 
    const Price = shirt_detail.substr(0, shirt_detail.indexOf(' ')) 
 
    const ImageURL = $('.shirt-picture').find('img').attr('src') 
 
    const URL = link 
 

 
    return new Shirt(Title, Price, ImageURL, URL) 
 
} 
 

 
let getAllProductsShirtsBody = (body) => { 
 
    const $ = cheerio.load(body) 
 
    
 
    return Promise.all($('.products').find('a').map((index, val) => { 
 
    return getShirtDetailsBody(`rootURL${$(val).attr('href')}`) 
 
    })) 
 
} 
 

 
getAllProductsShirtsBody(yourbody).then(allShirtsBody => { 
 
    const allShirts = allShirtsBody.map(shirtBody => { return getShirt(shirtBody) }) 
 
    console.log(allShirts) 
 
}).catch(err => { console.log(err) })

相关问题