如何对Node.js中具有承诺的API进行递归请求?

时间:2017-08-07 16:41:18

标签: javascript node.js express promise

我需要从API中读取数据,每个查询只能提供100个结果,以及从下一步获取100个结果的时间戳。

我已经设法使用下面的代码一个接一个地执行多个请求,但由于某种原因它永远不会返回到原始的承诺。它被困在“没有更多的订单来取回”。

app.get('/test', (req, res) => {

  const getOrders = (from) => {
    return request(mcfApiUrl + "changes?created_after_ts="+from+"&key="+mcfKey)
    .then(xml => convert.xmlDataToJSON(xml,{explicitArray:false,mergeAttrs:true}))
    .then(orders => checkForMore(orders));
  }

  const checkForMore = (orders) => {
    return new Promise((resolve, reject) => {
      if (orders['Orders']['orders'] == 100){
        getOrders(orders['Orders']['time_to']);
        console.log("Fetched "+ orders['Orders']['orders']+" orders");
        console.log("More orders available from: "+moment(orders['Orders']['time_to']*1000).format());
      }
      else {
        console.log("Fetched "+ orders['Orders']['orders']+" orders");
        console.log("No more orders to fetch");
        resolve(orders);
      }
    });
  };

  var fromdate = 1483999200;

  getOrders(fromdate)
  .then(output => res.send("Done")) // It never gets here
  .catch(err => console.log(err));

});

我错过了什么?

1 个答案:

答案 0 :(得分:3)

您的问题是您没有解决所有选项的checkForMore承诺。

const checkForMore = (orders) => {
    return new Promise((resolve, reject) => {
      if (orders['Orders']['orders'] == 100){
        getOrders(orders['Orders']['time_to']); // <-- not resolved
      }
      else {
        resolve(orders);
      }
    });
  };

只需将getOrdersresolve一起打包即可解决问题。

resolve(getOrders(orders['Orders']['time_to']))

但是,您并不需要创建新的承诺:

const checkForMore = (orders) => 
  orders['Orders']['orders'] == 100
    ? getOrders(orders['Orders']['time_to'])
    : Promise.resolve(orders);

事实上,你的整个功能可以缩小为几行:

const getOrders = (from) => 
  request(mcfApiUrl + "changes?created_after_ts="+from+"&key="+mcfKey)
    .then(xml => convert.xmlDataToJSON(xml,{explicitArray:false,mergeAttrs:true}))
    .then(orders => 
      orders.Orders.orders == 100
        ? getOrders(orders.Orders.time_to)
        : Promise.resolve(orders)
    );

现在,如果你想累积所有订单,你需要通过递归级别维持一些状态。

您可以使用全局状态或其他参数执行此操作:

const getOrders = (from, allOrders = []) => 
  //                     ^ accumulation container
  request(mcfApiUrl + "changes?created_after_ts="+from+"&key="+mcfKey)
    .then(xml => convert.xmlDataToJSON(xml,{explicitArray:false,mergeAttrs:true}))
    .then(orders => {
      allOrders.push(orders); // <-- accumulate
      return orders.Orders.orders == 100
        ? getOrders(orders.Orders.time_to, allOrders) // <-- pass through recursion
        : Promise.resolve(allOrders)
    });