所以你想按顺序做 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": [...]
},
...
]
}
旁注:将数组写入 json 是不必要的size
。results
这个值可以很容易地从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