Node.js - 所有异步调用完成后如何返回

时间:2017-06-13 02:16:46

标签: javascript node.js

如下所示,我将对象link_to_json返回到allShirts中声明的数组html_to_json

但是,最后一行的console.dirhtml_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;
}

2 个答案:

答案 0 :(得分:2)

有几种方法可以解决这个问题,但我喜欢这个Async库。

我如何处理你的问题的方法是先实际获取所有的网址,这样就可以改变你的身体了:

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将它们映射到提取数据的异步函数:

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

答案 1 :(得分:2)

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

&#13;
&#13;
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) })
&#13;
&#13;
&#13;