我需要在获取API的结果后需要使用请求承诺递归调用API,需要在excel文件中写入,下面给出API样本响应
{
"totalRecords": 9524,
"size": 20,
"currentPage": 1,
"totalPages": 477,
"result": [{
"name": "john doe",
"dob": "1999-11-11"
},
{
"name": "john1 doe1",
"dob": "1989-12-12"
}
]
}
现在我想调用这个API n次,这里n等于totalPages,在调用每个API之后我想将响应结果写入excel文件。 首先将第1页的响应结果写入excel,然后将第2页的响应结果附加到excel文件,依此类推。 我已经写了一些示例代码,如下所示
function callAPI(pageNo) {
var options = {
url: "http://example.com/getData?pageNo="+pageNo,
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
json: true
}
return request(options)
}
callAPI(1).then(function (res) {
// Write res.result to excel file
}).catch(function (err) {
// Handle error here
})
但是面对问题调用递归API和顺序维护就像写第1页结果首先到excel文件然后第2页结果追加到excel等等。 任何代码示例如何在nodejs中实现
答案 0 :(得分:1)
你想做这样的事情:
function getAllPages() {
function getNextPage(pageNo) {
return callAPI(pageNo).then(response => {
let needNextPage = true;
if (pageNo === 1) {
// write to file
} else {
// append to file
}
if (needNextPage) {
return getNextPage(pageNo+1);
} else {
return undefined;
}
});
}
return getNextPage(1);
}
显然要改变“需要下一页”'在你完成时停止递归
答案 1 :(得分:1)
所以你想按顺序做477个请求?你要等多久才能完成这个?即使是在并列中,这对我来说仍然太长了。
最佳:编写一个可以一次返回一批页面的API。减少对后端的请求数量。也许像http://example.com/getData?pages=1-100
之类的东西让它返回一个数组;也许像
[
{
"totalRecords": 9524,
"currentPage": 1,
"totalPages": 477,
"result": [...]
},
{
"totalRecords": 9524,
"currentPage": 2,
"totalPages": 477,
"result": [...]
},
...
]
或更紧凑
{
"totalRecords": 9524,
"totalPages": 477,
"pages": [
{
"currentPage": 1,
"result": [...]
},
{
"currentPage": 2,
"result": [...]
},
...
]
}
旁注:将size
数组的results
写入json是不必要的。可以从data.result.length
伊莫。您想按顺序运行的只是将页面添加到工作表中。请求可以在并列中完成。这已经为整个任务节省了大量的整体运行时间。
callApi(1).then(firstPage => {
let {currentPage, totalPages} = firstPage;
//`previous` ensures that the Promises resolve in sequence,
//even if some later request finish sooner that earlier ones.
let previous = Promise.resolve(firstPage).then(writePageToExcel);
while(++currentPage <= totalPages){
//make the next request in paralell
let p = callApi(currentPage);
//execute `writePageToExcel` in sequence
//as soon as all previous ones have finished
previous = previous.then(() => p.then(writePageToExcel));
}
return previous;
})
.then(() => console.log("work done"));
或等待所有页面加载,然后再将它们写入excel
callApi(1).then(firstPage => {
let {currentPage, totalPages} = firstPage;
let promises = [firstPage];
while(++currentPage < totalPages)
promises.push(callApi(currentPage));
//wait for all requests to finish
return Promise.all(promises);
})
//write all pages to excel
.then(writePagesToExcel)
.then(() => console.log("work done"));
或者您可以批量处理请求
callApi(1).then(firstPage => {
const batchSize = 16;
let {currentPage, totalPages} = firstPage;
return Promise.resolve([ firstPage ])
.then(writePagesToExcel)
.then(function nextBatch(){
if(currentPage > totalPages) return;
//load a batch of pages in paralell
let batch = [];
for(let i=0; i<batchSize && ++currentPage <= totalPages; ++i){
batch[i] = callApi(currentPage);
}
//when the batch is done ...
return Promise.all(batch)
//... write it to the excel sheet ...
.then(writePagesToExcel)
//... and process the next batch
.then(nextBatch);
});
})
.then(() => console.log("work done"));
但不要忘记添加错误处理。由于我不确定您是如何处理我发布的方法的错误,因此我没有在此处包含错误处理。
你可以修改批处理请求,得到一些错误,你在哪里分配toalPages,这是不正确的,为什么totalPages应该等于firstPage
let {currentPage, totalPages} = firstPage;
//is just a shorthand for
let currentPage = firstPage.currentPage, totalPages = firstPage.totalPages;
//what JS version are you targeting?
第一个请求callApi(1).then(firstPage => ...)
主要用于确定currentIndex
和totalLength
,因为您在返回的JSON中提供了这些属性。现在我知道了这两个,我可以按照我的意愿在并列中发起尽可能多的请求。而且我不必等待他们中的任何一个完成以确定我的索引,并且还有更多的页面要加载。
以及为什么要撰写
return Promise.resolve([ firstPage ])
为了省去一些麻烦和检查,因为我对你如何实施writePagesToExcel
一无所知。
我return Promise.resolve(...)
所以我可以做.then(writePagesToExcel)
。这解决了我两个问题:
我不必关心writePagesToExcel
返回同步或承诺,我可以随时跟进另一个.then(...)
我不需要关心writePagesToExcel
可能会抛出。如果出现任何错误,它们都会在Promise链中结束,并且可以在那里进行处理。
所以最终我通过简单地将firstPage
包裹在Promise中并继续使用.then(...)
来保护自己一些检查。考虑到您在此处理的数据量,imo。这不是太多的开销,以摆脱一些潜在的陷阱。
为什么要像解决方案一样传递数组
在每个例子中保持一致。在这个例子中,我命名了处理数据writePagesToExcel
(复数)的函数,它应该表明它处理多个页面(它们的数组);我认为在这种情况下这很清楚。
因为我仍然需要在开始时单独调用以获得firstPage
,并且我不想使nextBatch
中的逻辑复杂化只是为了将第一页连接到第一页,我对待[firstPage]
作为单独的“批处理”,将其写入Excel并继续nextBatch
答案 2 :(得分:-1)
function callAPI(pageNo) {
var options = {
url: "http://example.com/getData?pageNo="+pageNo,
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
json: true
}
return request(options)
}
function writeToExcel(res){console.log(res)} //returns promise.
callAPI(1).then(function (res) {
if(res){
writeToExcel(res).then(() => {
var emptyPromise = new Promise(res => setTimeout(res, 0));
while(res && res.currentPage < res.totalPages){
emptyPromise = emptyPromise.then(() => {
return callAPI(res.currentPage).then(function (res){
if(res){
writeToExcel(res)
}
});
}
}
return emptyPromise;
});
}
}).catch(function (err) {
// Handle error here
})