以异步方式以正确的顺序连接API响应

时间:2016-07-09 14:41:29

标签: node.js asynchronous

所以我在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
[]

当我将其注销时,为什么我的问题变量为空?显然有结果与它相结合。

一个更普遍的问题:这种方法是解决我想要实现的目标的最佳方式吗?我认为即使我的代码确实有效,异步性的本质也意味着结果可能以错误的顺序连接起来。

我应该只使用同步请求库吗?

1 个答案:

答案 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
})