2017-06-13 102 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) })

相關問題