如何在Node.js中对promise做recursion请求?

我需要从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)); }); 

我错过了什么?

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

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

只要用resolvescheme包装调用getOrders就可以解决这个问题。

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

但是,你并不需要创造一个新的承诺:

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

实际上,你的整个function可以缩减成几行:

 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) ); 

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

你可以用全局状态或其他参数来做到这一点:

 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) });