Javascript 如何进行顺序HTTP调用?
我需要调用几个API来收集和合并信息。 我进行了第一个API调用,并根据结果对第二个API进行了多次调用(在循环中)。 因为http请求是异步的,所以我丢失了信息。当第二步完成时,服务器(nodejs)已经将响应发送回客户端 我已经尝试过,不知怎么地,使用回调函数。这使得客户端的响应保持等待,但第二次呼叫的信息仍然丢失。我猜这些变量没有被同步。 我还使用away/async做了一个快速测试,但我的Javascript mojo不足以让它无误运行Javascript 如何进行顺序HTTP调用?,javascript,node.js,httprequest,Javascript,Node.js,Httprequest,我需要调用几个API来收集和合并信息。 我进行了第一个API调用,并根据结果对第二个API进行了多次调用(在循环中)。 因为http请求是异步的,所以我丢失了信息。当第二步完成时,服务器(nodejs)已经将响应发送回客户端 我已经尝试过,不知怎么地,使用回调函数。这使得客户端的响应保持等待,但第二次呼叫的信息仍然丢失。我猜这些变量没有被同步。 我还使用away/async做了一个快速测试,但我的Javascript mojo不足以让它无误运行 /* pseudo code */ functio
/* pseudo code */
function getData(var1, callback){
url= "http://test.server/bla?param="+var1;
request.get(url, function (error, response, body){
var results = [];
for(var item of JSON.parse(body).entity.resultArray) {
var o = {};
o['data1'] = item.data1;
o['data2'] = item.data2;
o['data3'] = item.data3;
getSecondStep(o, function(secondStepData){
//console.log("Callback object");
//console.log(o);
o['secondStepData'] = secondStepData;
});
results.push(o);
}
callback(results);
});
}
function getSecondStep(object, callback){
url = "http://othertest.server/foobar?param=" + object.data1;
request.get(url, function (error, response, body){
var results = [];
if(response.statusCode == 200){
for(var item of JSON.parse(body).object.array) {
var o = {}
o['data4'] = item.data4;
o['data5'] = item.data5;
results.push(o);
}
callback(results);
}
});
}
我希望能够将所有信息收集到一个JSON对象中,并将其返回给客户端。
然后,客户端将负责以良好的方式呈现它。只有在调用了所有第二个
回调
函数后,才需要调用第一个函数的回调
。尝试以下更改:
function getData(var1, callback) {
url = "http://test.server/bla?param=" + var1;
request.get(url, function (error, response, body) {
var results = [],count=0;
var arr = JSON.parse(body).entity.resultArray;
for (let [index, value] of arr.entries()) {
var o = {};
o['data1'] = item.data1;
o['data2'] = item.data2;
o['data3'] = item.data3;
getSecondStep(o, function (secondStepData) {
//console.log("Callback object");
//console.log(o);
o['secondStepData'] = secondStepData;
results[index] = o;
count++;
if (count === arr.length) {
callback(results);
}
});
}
});
}
我建议您使用支持承诺(例如:)的库,因为代码比回调方法更容易处理 您的代码看起来像:
function getData(var1){
var url = "http://test.server/bla?param="+var1;
return request.get(url).then(result1 => {
var arr = JSON.parse(body).entity.resultArray;
return Promise.all( arr.map(x => request.get("http://othertest.server/foobar?param=" + result1.data1)))
.then(result2 => {
return {
data1: result1.data1,
data2: result1.data2,
data3: result1.data3,
secondStepData: result2.map(x => ({data4:x.data4, data5:x.data5}))
}
})
});
}
而且用法也会很简单
getData("SomeVar1").then(result => ... );
我建议在库中使用async/await模式 这使得API调用非常容易,并且在使用此模式时代码更干净 在下面的示例中,我只是调用一个httpbin API来生成一个UUID,但该原则适用于任何API
const rp = require('request-promise-native');
async function callAPIs() {
let firstAPIResponse = await rp("https://httpbin.org/uuid", { json: true });
console.log("First API response: ", firstAPIResponse);
// Call several times, we can switch on the first API response if we like.
const callCount = 3;
let promiseList = [...Array(callCount).keys()].map(() => rp("https://httpbin.org/uuid", { json: true }));
let secondAPIResponses = await Promise.all(promiseList);
return { firstAPIResponse: firstAPIResponse, secondAPIResponses: secondAPIResponses };
}
async function testAPIs() {
let combinedResponse = await callAPIs();
console.log("Combined response: " , combinedResponse);
}
testAPIs();
在这个简单的示例中,我们得到如下组合响应:
{
{
firstAPIResponse: { uuid: '640858f8-2e69-4c2b-8f2e-da8c68795f21' },
secondAPIResponses: [
{ uuid: '202f9618-f646-49a2-8d30-4fe153e3c78a' },
{ uuid: '381b57db-2b7f-424a-9899-7e2f543867a8' },
{ uuid: '50facc6e-1d7c-41c6-aa0e-095915ae3070' }
]
}
}
问题是,您在调用回调的同时仍在进行异步调用。有几种方法是可能的,比如我们使用async/await,或者恢复承诺(在您的情况下,我可能会这么做) 或者,您也可以只在掌握了所有可用信息的情况下调用回调函数。伪代码如下:
function getData(var1, callback){
url= "http://test.server/bla?param="+var1;
request.get(url, function (error, response, body){
var results = [];
var items = JSON.parse(body).entity.resultArray;
var done = 0, max = items.length;
for(var item of items) {
var o = {};
o['data1'] = item.data1;
o['data2'] = item.data2;
o['data3'] = item.data3;
getSecondStep(o, function(secondStepData){
//console.log("Callback object");
//console.log(o);
o['secondStepData'] = secondStepData;
results.push(o);
done += 1;
if(done === max) callback(results);
});
}
});
}
(请注意,由于这是伪代码,因此我不会检查错误或处理来自
请求的可能的空结果。get(…)
)如果(results.length==arr.length)
在最后一次结果后为真。push(o)代码>在第一个o['secondStepData']=secondStepData之前代码>已执行。True。在@Thomasnow进行更改您只需确保订单得到保留。返回数据与预期不一样。所有的secondStepData
是所有second
调用的数组,我将使用let promissions=[]。。。承诺。推送(rp(…)。。。让我们等待承诺代码>以便这些请求可以并行运行。是的,这是一个很好的方法!完美的我第一次尝试用计数器“让它工作”,但共享对象变得一团糟。有了这个解决方案,我真的成功了。因为它只是一个POC,所以我没有并行化任何东西,但这应该是一个简单的改进。