[英]NodeJS REST API wait for response
我试图从API获取一堆ID,然后形成一系列请求,这些请求将进一步调用API以获取一些参数。 这些将总计,我希望输出结果将作为JSON数组推送。
问题是REST调用是异步的,我已经做出了承诺,但是不确定何时将承诺解析回调用函数,其余的调用有时需要一到两秒钟才能回复。
我想知道在什么时候可以兑现承诺,或者如何知道何时计算出总额?
路线
app.get("/sonar/:x_id",function(req,resp) {
getRestSonar(req.params.x_id).then(function (fromResolve) {
resp.send(fromResolve);
});
});
带promise的函数使其余的调用循环
var getRestSonar = function(requestX) {
return new Promise(function(resolve,reject) {
var unirest = require("unirest");
var reqx = unirest("GET", "http://sonarqubexxServer/api/projects");
var outputJson = {
table: []
};
reqx.end(function (res) {
if (res.error) throw new Error(res.error);
// console.log(res.body);
var result = res.body;
//var needle = req.params.csi_id;
var needle = requestX;
var TotalDuplicateLines = 0;
var TotalBugs = 0;
var TotalNcloc = 0;
var TotalCodeSmells = 0;
var TotalVulnerabilities = 0;
for (var i=0;i<result.length;i++) {
if (result[i].nm.indexOf(needle) !== -1) {
console.log(result[i].k);
var queryUrl = "http://sonarqubexxServer/api/resources?resource="+result[i].k+"&metrics=code_smells,bugs,vulnerabilities,ncloc,coverage,duplicated_lines&format=json"
console.log(queryUrl);
var subrequest = unirest("GET",queryUrl);
subrequest.end(function (resXX) {
if (resXX.error);
var resXXResult = resXX.body;
for (var i=0;i<resXXResult.length;i++) {
// var duplicateData = resXXResult[0].msr.filter(item => item.key == 'duplicated_lines');
resXXResult[i].msr.forEach(m => {
if (m.key === 'duplicated_lines') {
console.log('Duplicated Lines ' + m.val);
TotalDuplicateLines += m.val;
}
else if(m.key === 'bugs' ) {
console.log('Bugs ' + m.val);
TotalBugs += m.val;
}
else if(m.key === 'ncloc' ) {
console.log('Lines of Code ' + m.val);
TotalNcloc += m.val;
}
else if(m.key === 'code_smells' ) {
console.log('Code Smells ' + m.val);
TotalCodeSmells += m.val;
}
else if(m.key === 'vulnerabilities' ) {
console.log('Vulnerabilities ' + m.val);
TotalVulnerabilities += m.val;
outputJson.table.push({totduplines:TotalDuplicateLines},{totVul:TotalVulnerabilities});
}
});
console.log("Iam here with I :: " + i);
if (i === (resXXResult.length - 1)) {
//Should i resolve here makes no sense
console.log("Resolved the promise now..");
}
//The for ends here
}
// I see this is a bad place to resolve..
resolve(outputJson);
});
}
}
});
});
}
编辑:如注释中所建议,将调用分成较小的部分
现在,我获取api调用,分别从中创建一个数组,然后使用promises回调到API? 我如何通过循环解决每个呼叫? 当我尝试循环时,它始终会解析request[0]
,然后脱离promise,我如何创建一个promise数组并等待它们完成?
app.get("/sonar/:csi_id",function(req,resp) {
var collectiveResult = [];
getRestSonar(req.params.csi_id).then(function (fromResolve) {
return splitReqUrl(fromResolve);
}).then(function(fromSplitUrl) {
console.log("I am from split url ::::" + fromSplitUrl);
return getSubSonarProperties(fromSplitUrl);
}).then(function(fromsubSonar) {
collectiveResult.push(fromsubSonar);
console.log("+++++++++++++++++++++++++++");
console.log(fromsubSonar);
resp.send(collectiveResult);
});
});
var getSubSonarProperties = function(getUrl) {
return new Promise(function(resolve,reject) {
var getSubRest = require("unirest");
console.log("Attempting to GET " + getUrl);
var req = getSubRest("GET",getUrl);
var outputJson = {
table: []
}
var TotalDuplicateLines = 0;
var TotalBugs = 0;
var TotalNcloc = 0;
var TotalCodeSmells = 0;
var TotalVulnerabilities = 0;
req.end(function (res) {
if (res.error);
var resXXResult = res.body;
resolve(resXXResult);
});
});
}
var splitReqUrl = function(request) {
return new Promise(function(resolve,reject) {
resolve(request[1]);
//for(var i=0; i< request.length; i++) {
// resolve(request[i]);
//}
});
}
var getRestSonar = function(requestX) {
return new Promise(function(resolve,reject) {
var unirest = require("unirest");
var reqx = unirest("GET", "http://sonarqubexxx/api/projects");
var outputJson = {
table: []
};
reqx.end(function (res) {
if (res.error) throw new Error(res.error);
// console.log(res.body);
var result = res.body;
//var needle = req.params.csi_id;
var needle = requestX;
var queryArray = [];
for (var i=0;i<result.length;i++) {
if (result[i].nm.indexOf(needle) !== -1) {
console.log(result[i].k);
var queryUrl = "http://sonarxxx/api/resources?resource="+result[i].k+"&metrics=code_smells,bugs,vulnerabilities,ncloc,coverage,duplicated_lines&format=json"
//console.log(queryUrl);
queryArray.push(queryUrl);
}
if (i === (result.length - 1)) {
resolve(queryArray);
}
}
});
});
}
首先,您的解决方案存在的问题是,您试图将所有内容都放入一个new Promise(...)
大型创建器中。
即使您设法完成该工作, 它仍然是一种常见的反模式,因为使用.then(...)
方法将Promises 链接 .then(...)
。
正如Roamer-1888所指出的,应该有一个unirest
的分叉, unirest
可以直接处理Promises,而不是像您的示例中那样要求回调,但是在这里unirest
的版本。
因此,您需要做的是创建一个Promise链来处理代码的不同步骤,并将结果传递给链。
您的步骤似乎是:
requestX
输入过滤结果。 outputJson
对象。 基本上,唯一的异步步骤是1和3,但是可以添加第三步来构建您的outputJson
并将其传递给下游,这是可以的。
因此,让我们从第一步开始。
在Promise链的第一个链接中,我们需要使用您的第一个unirest
调用来检索初始结果:
new Promise((resolve, reject) => {
unirest("GET", "http://sonarqubexxServer/api/projects")
.end((res) => {
if (res.error) {
reject(res.error);
} else {
resolve(res.body);
}
});
})
在此示例中看到,我已经检查了响应是否包含错误并在这种情况下触发了拒绝,否则我将使用主体(我们需要的数据)来解决promise。
如果请求失败,我们上面创建的Promise将引发错误,如果一切正常,将在响应的主体下游。
现在,我们可以继续使用.then(...)
方法来充分利用Promises的潜力:
new Promise((resolve, reject) => {
unirest("GET", "http://sonarqubexxServer/api/projects")
.end((res) => {
if (res.error) {
reject(res.error);
} else {
resolve(res.body);
}
});
}).then((results) => {
results = results.filter((result) => {
return result.nm.indexOf(request) != -1;
});
return Promise.all(results.map((result) => {
return new Promise((resolve, reject) => {
var queryUrl = "http://sonarqubexxServer/api/resources?resource=" + result.k + "&metrics=code_smells,bugs,vulnerabilities,ncloc,coverage,duplicated_lines&format=json"
unirest("GET", queryUrl)
.end((res) => {
if (res.error) {
reject(res.error);
} else {
resolve(res.body);
}
});
})
}))
})
在这一步中,我使用了一些Array
方法来使代码更干净, Promise.all
可以一起处理多个promise。
Array.filter
是一种迭代数组并检查每个项目是否应保留在过滤输出中的方法。 因此,在您的情况下,我们只想保留result.nm.indexOf(request) != -1
那些项目。
Array.map
是一种迭代数组并将每个项目转换为其他内容的方法。 基本上,您提供的函数将每个项目作为输入,将其转换为其他内容,然后将此新值替换为输出数组中的旧值。
最后, Promise.all
接受一个Promises数组并返回Promise本身。 当所有给定的Promise都解析后,此返回的Promise将解析,并将向下游传递哪些项是每个单个Promise的结果。
因此,通过编写Promise.all(results.map((results) => { return new Promise(...) }))
我们将结果数组中的每个结果转换为执行特定于结果的调用的Promise,并将其放入Promise.all
的Promises输出数组,因此它们可以立即执行。
现在,Promise链输出Promise.all
的结果,该结果是每个Promise的所有结果的数组,这些结果是每个子调用的结果。
然后,我们可以简单地获取下游数据,并使用嵌套的迭代来构建outputJSON
传递给下游:
new Promise((resolve, reject) => {
unirest("GET", "http://sonarqubexxServer/api/projects")
.end((res) => {
if (res.error) {
reject(res.error);
} else {
resolve(res.body);
}
});
}).then((results) => {
results = results.filter((result) => {
return result.nm.indexOf(request) != -1;
});
return Promise.all(results.map((result) => {
return new Promise((resolve, reject) => {
var queryUrl = "http://sonarqubexxServer/api/resources?resource=" + result.k + "&metrics=code_smells,bugs,vulnerabilities,ncloc,coverage,duplicated_lines&format=json"
unirest("GET", queryUrl)
.end((res) => {
if (res.error) {
reject(res.error);
} else {
resolve(res.body);
}
});
})
}))
}).then((allResults) => {
var TotalDuplicateLines = 0;
var TotalBugs = 0;
var TotalNcloc = 0;
var TotalCodeSmells = 0;
var TotalVulnerabilities = 0;
var outputJson = {
table: []
};
for (var i = 0; i < allResults; i++) {
for (var j = 0; j < allResults[i].length; j++) {
allResults[i][j].msr.forEach(m => {
if (m.key === 'duplicated_lines') {
TotalDuplicateLines += m.val;
}
else if (m.key === 'bugs') {
TotalBugs += m.val;
}
else if (m.key === 'ncloc') {
TotalNcloc += m.val;
}
else if (m.key === 'code_smells') {
TotalCodeSmells += m.val;
}
else if (m.key === 'vulnerabilities') {
TotalVulnerabilities += m.val;
outputJson.table.push({ totduplines: TotalDuplicateLines }, { totVul: TotalVulnerabilities });
}
});
}
}
return outputJson;
})
如果您在getRestSonar(request)
函数中返回了这条较长的Promise链,则可以编写getRestSonar(request).then((outputJson) => { ... do something with your outputJson ... })
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.