繁体   English   中英

NodeJS REST API等待响应

[英]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链来处理代码的不同步骤,并将结果传递给链。

您的步骤似乎是:

  1. 进行第一次调用以检索初始结果。
  2. 根据requestX输入过滤结果。
  3. 对于剩下的每个项目,进行几次调用以获取更多数据。
  4. 将所有内容放回outputJson对象。

基本上,唯一的异步步骤是1和3,但是可以添加第三步来构建您的outputJson并将其传递给下游,这是可以的。

因此,让我们从第一步开始。

1.打个电话

在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将引发错误,如果一切正常,将在响应的主体下游。

2.过滤和子呼叫

现在,我们可以继续使用.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输出数组,因此它们可以立即执行。

3.构建outputJSON

现在,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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM