所以我在API周围构建一个简单的包装器来获取特定实体的所有结果。 API方法一次最多只能返回500个结果,但可以使用skip
参数检索所有结果,该参数可用于指定开始检索结果的索引。 API还有一个方法,它返回总共存在的结果数。
我花了一些时间与request
包进行斗争,试图想出一种方法来按顺序连接所有结果,然后执行一个回调,通过所有结果。
这是我目前的代码:
Donedone.prototype.getAllActiveIssues = function(callback){
var url = this.url;
request(url + `/issues/all_active.json?take=500`, function (error, response, body) {
if (!error && response.statusCode == 200) {
var data = JSON.parse(body);
var totalIssues = data.total_issues;
var issues = [];
for (let i=0; i < totalIssues; i+=500){
request(url + `/issues/all_active.json?skip=${i}&take=500`, function (error, response, body){
if (!error && response.statusCode == 200) {
console.log(JSON.parse(body).issues.length);
issues.concat(JSON.parse(body).issues);
console.log(issues); // returns [] on all occasions
//callback(issues);
} else{
console.log("AGHR");
}
});
}
} else {
console.log("ERROR IN GET ALL ACTIVE ISSUES");
}
});
};
所以我开始使用空数组issues
。我遍历for循环,每次将i
增加500并将其作为skip
参数传递。如您所见,我在记录每个响应包含的主题issues
变量之前记录了多少个问题的长度。
输出,总共869个结果是:
369
[]
500
[]
当我将其注销时,为什么我的问题变量为空?显然有结果与它相结合。
一个更普遍的问题:这种方法是解决我想要实现的目标的最佳方式吗?我认为即使我的代码确实有效,异步性的本质也意味着结果可能以错误的顺序连接起来。
我应该只使用同步请求库吗?
答案 0 :(得分:1)
当我将其注销时,为什么我的问题变量为空?有明确的 结果与它相结合。
这里的一个主要问题是.concat()
返回一个新数组。它不会将项添加到现有数组中。
你可以改变这个:
issues.concat(JSON.parse(body).issues);
到此:
issues = issues.concat(JSON.parse(body).issues);
确保保留新的连锁数组。这是一个非常常见的错误。
您的阵列中也可能存在排序问题,因为您正在运行for
循环,该循环同时启动一大堆请求,结果可能会或可能不会以正确的顺序返回。您仍然可以获得正确的问题总数,但它们可能不符合要求的顺序。我不知道这对你是否有问题。如果这是一个问题,我们也可以建议修复它。
一个更普遍的问题:这种方法是最好的方法 我想要实现的目标是什么?我想即使我的代码确实有效, 异步性的本质意味着它完全有可能 结果以错误的顺序连接。
除了可以修复的订购问题外,这是一种合理的做事方式。我们需要了解有关您的API的更多信息,以了解这是否是使用API获取结果的最有效方式。通常,您希望避免对同一服务器进行N次重复API调用,而是进行一次API调用以获取所有结果。
我应该只使用同步请求库吗?
绝对不是。 node.js需要学习如何进行异步编程。对于大多数人来说,这是一个学习步骤,但是你是如何从node.js获得最佳性能的,应该学习和使用它。
这是一种使用promises进行同步和错误传播的可靠顺序收集所有结果的方法(这对于node.js中的异步处理非常有用):
// promisify the request() function so it returns a promise
// whose fulfilled value is the request result
function requestP(url) {
return new Promise(function(resolve, reject) {
request(url, function(err, response, body) {
if (err || response.statusCode !== 200) {
reject({err: err, response: response});
} else {
resolve({response: response, body: body});
}
});
});
}
Donedone.prototype.getAllActiveIssues = function() {
var url = this.url;
return requestP(url + `/issues/all_active.json?take=500`).then(function(results) {
var data = JSON.parse(results.body);
var totalIssues = data.total_issues;
var promises = [];
for (let i = 0; i < totalIssues; i+= 500) {
promises.push(requestP(url + `/issues/all_active.json?skip=${i}&take=500`).then(function(results) {
return JSON.parse(results.body).issues;
}));
}
return Promise.all(promises).then(function(results) {
// results is an array of each chunk (which is itself an array) so we have an array of arrays
// now concat all results in order
return Array.prototype.concat.apply([], results);
})
});
}
xxx.getAllActiveIssues().then(function(issues) {
// process issues here
}, function(err) {
// process error here
})