使用承诺收集未知大小的分页数据

我正在查询REST-API来获取所有组。 这些小组分成五十批。我想收集所有这些小组,然后继续处理它们。

直到现在,我依靠callback,但我想使用承诺来链接所有组的检索,然后进一步处理结果数组。

我只是不太了解如何使用promise来取代recursion函数调用。

我将如何使用A + promise来逃避我用这个代码创build的callback地狱?

function addToGroups() { var results = [] collectGroups(0) function collectGroups(offset){ //async API call sc.get('/tracks/'+ CURRENT_TRACK_ID +'/groups?limit=50&offset=' + offset , OAUTH_TOKEN, function(error, data){ if (data.length > 0){ results.push(data) // keep requesting new groups collectGroups(offset + 50) } // finished else { //finish promise } }) } } 

使用标准的承诺,包装所有现有的代码如下所示:

 function addToGroups() { return new Promise(function(resolve, reject) { ... // your code, mostly as above }); } 

在你的代码中,当你完成时调用resolve(data) ,或者如果由于某种原因导致调用失败,则reject()

为了使整个事情更“承诺”,首先做一个函数collectGroups返回一个承诺:

 function promiseGet(url) { return new Promise(function(resolve, reject) { sc.get(url, function(error, data) { if (error) { reject(error); } else { resolve(data); } }); } } // NB: promisify-node can do the above for you function collectGroups(offset, stride) { return promiseGet('/tracks/'+ CURRENT_TRACK_ID +'/groups?limit=' + stride + '&offset=' + offset , OAUTH_TOKEN); } 

然后在你的代码中使用这个Promise:

 function addToGroups() { var results = [], stride = 50; return new Promise(function(resolve, reject) { (function loop(offset) { collectGroups(offset, stride).then(function(data) { if (data.length) { results.push(data); loop(offset + stride); } else { resolve(data); } }).catch(reject); )(0); }); } 

这可以工作。 我正在使用https://github.com/kriskowal/q承诺。

  var Q = require('q'); function addToGroups() { var results = [] //offsets hardcoded for example var a = [0, 51, 101]; var promises = [], results; a.forEach(function(offset){ promises.push(collectGroups(offset)); }) Q.allSettled(promises).then(function(){ promises.forEach(function(promise, index){ if(promise.state === 'fulfilled') { /* you can use results.concatenate if you know promise.value (data returned by the api) is an array */ //you also could check offset.length > 0 (as per your code) results.concatenate(promise.value); /* ... do your thing with results ... */ } else { console.log('offset',index, 'failed', promise.reason); } }); }); } function collectGroups(offset){ var def = Q.defer(); //async API call sc.get('/tracks/'+ CURRENT_TRACK_ID +'/groups?limit=50&offset=' + offset , OAUTH_TOKEN, function(error, data){ if(!err) { def.resolve(data); } else { def.reject(err); } }); return def.promise; } 

让我知道如果它的作品。

这里是完整的例子,使用spex.sequence :

 var spex = require("spex")(Promise); function source(index) { return new Promise(function (resolve) { sc.get('/tracks/' + CURRENT_TRACK_ID + '/groups?limit=50&offset=' + index * 50, OAUTH_TOKEN, function (error, data) { resolve(data.length ? data : undefined); }); }); } spex.sequence(source, {track: true}) .then(function (data) { // data = all the pages returned by the sequence; }); 

我不认为它可以比这更简单;)