从API获取分页的项目列表

时间:2018-02-05 20:11:03

标签: javascript node.js promise axios

我需要从API端点(/ products)获取项目列表,但它们是分页的(每页最多200个项目)。

我需要制作一个循环,它将获得200个产品,推送到阵列,并增加页码,因此它可以要求更多200个产品。它会在404错误(页面不存在)时停止,这意味着我得到了所有产品。

我正在使用Axios来处理请求,这是基于Promise的,但我无法让它工作。我尝试了几件事,甚至创建了自己的Promise,但结果是一样的:

  • 无法让它等待所有要求的页面
  • 它总是会请求同一页面,因为页面增量在里面。然后是承诺(确保我不会超越最后一页)

我知道Promises的想法是异步的,但我正试图找到一种方法让它发挥作用。

任何人都知道我可以使用什么逻辑来做到这一点?我想在继续之前获得所有项目。也许我过于复杂,一些澄清会有很多帮助。

编辑:

尝试以递归方式进行,但结果总是在执行之前返回:

module.exports = {
  sync(req, res) {
    // Get all products page by page
    var products = module.exports.getProductsByPage()
    res.status(200).send(products)
  },

  getProductsByPage(page = 1, products = []) {
    nuvemshop.get(`products?page=${page}&per_page=200`)
    .then(res => {
        console.log('GET Products PAGE ' + page)
        products.push(res.data)
        arguments.callee(++page, products)
    })
    .catch(e => {
        if(e.response.status === 404) {
            console.log('LAST PAGE REACHED')
            return products
        } else 
            return e
    })
  },

1 个答案:

答案 0 :(得分:1)

以下工作或是否会产生错误/意外结果?

const getProductsByPage = (page = 1, products = []) => 
  //you need to return the promise here, arrow without {} block
  //  returns the single statement (x=>y = function(x){return y;})
  nuvemshop.get(`products?page=${page}&per_page=200`)
  .then(res => {
    console.log('GET Products PAGE ' + page);
    //you need to return the promise here
    //  call recursively
    return getProductsByPage(
      page+1,
      products.concat(res.data)
    );
  })
  .catch(e => {
    if (e.response.status === 404) {
      console.log('LAST PAGE REACHED')
      return products
    } else
      return e
  });

const sync = (req, res) => {
  // Get all products page by page
  var products = getProductsByPage()
  .then(
    products=>
      res.status(200).send(products)
  ).catch(
    err => 
      res.status(500).send(err)
  );
};


module.exports = {
  sync
}

以下版本将一次获取10个页面而不是逐个获取。如果出现问题,它会生成Fail类型的结果,并删除404响应的Fail类型,但会保存任何其他失败原因:

const Fail = function(reason){this.reason = reason;};
const isFail = x=>(x&&x.constructor)===Fail;
const isNotFail = x=>!isFail(x);
const getProductsByPage = (pagesInSet=10) => {
  //set up max 3 requests per second
  //const max3 = throttlePeriod(3,1000);
  const recur = (startAt,products) =>
    Promise.all(
      Array.from(new Array(pagesInSet),(_,index)=>index+startAt)
      .map(
        page=>
          //for throttled
          //max3(nuvemshop.get.bind(nuvemshop))(`products?page=${page}&per_page=200`)
          nuvemshop.get(`products?page=${page}&per_page=200`)
          .catch(
            e=>new Fail(e,page)
          )
      )  
    ).then(
      resultSet=>{
        //check if any results came back with 404
        const needStop = resultSet
          .filter(isFail)
          .filter(
            fail=>{
              const [e] = fail;
              return e.response.status === 404;
            }
          );
        if(needStop.length!==0){
          const without404 = products.concat(
            resultSet.filter(
              result=>{
                if(isFail(result)){
                  const [e] = result;
                  return e.response.status !== 404;
                }
                return true;
              }
            )
          );
          return without404;
        }
        //get the next pagesInSet pages
        return recur(startAt+pagesInSet,products.concat(resultSet));
      }
    );
  return recur(1,[]);
}
const sync = (req, res) => {
  // Get all products in sets of 10 parallel requests
  var products = getProductsByPage(10)
  .then(
    products=> {
      //you may want to do something with failed request (non 404)
      //const failed = products.filter(isFail)
      res.status(200).send(products);
    }
  ).catch(
    err => 
      res.status(500).send(err)
  );
};

module.exports = {
  sync
}