在我的 Next.js 應用程式中,我嘗試使用順序呼叫 API 端點getStaticProps,我有第三方 API,它每秒只允許 5 個請求,我想在開始時執行前 5 個呼叫,然后等待特定時間并再呼叫 4 個呼叫,我嘗試用for of回圈實作順序請求,好像不行,所有的函式呼叫都是同時執行的。解決這個問題的正確方法是什么?
const asyncCalls = [
testApi1.getInfo1(),
testApi2.getInfo2(),
testApi3.getInfo3(),
testApi1.getInfo4(),
testApi2.getInfo5(),
testApi3.getInfo6(),
testApi1.getInfo7(),
testApi2.getInfo8(),
testApi3.getInfo9(),
]
function delayMyPromise(myPromise, myDelay) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
return resolve(myPromise)
}, myDelay)
})
}
const resolved = []
for (const item of asyncCalls) {
const response = await delayMyPromise(item, 1000)
resolved.push(response)
}
console.log(resolved)
uj5u.com熱心網友回復:
您可以使用批處理方法使用Promise.all(). 無需按順序發送請求。
此解決方案等待所有請求回傳,然后在發送下一個請求之前等待一秒鐘。
// list of items/ data that you might want to use to compose your request
let dataForCalls = [
{ info: 1 },
{ info: 2 },
{ info: 3 },
{ info: 4 },
{ info: 5 },
{ info: 6 },
{ info: 7 },
{ info: 8 },
{ info: 9 },
];
const waitForMs = (ms) => new Promise((resolve, reject) => setTimeout(() => resolve(), ms));
(async () => {
// number of concurrent requests in one batch
const batchSize = 5;
// request counter
let curReq = 0;
// as long as there are items in the list continue to form batches
while (curReq < dataForCalls.length) {
// a batch is either limited by the batch size or it is smaller than the batch size when there are less items required
const end = dataForCalls.length < curReq batchSize ? dataForCalls.length: curReq batchSize;
// we know the number of concurrent request so reserve memory for this
const concurrentReq = new Array(batchSize);
// issue one request for each item in the batch
for (let index = curReq; index < end; index ) {
concurrentReq.push(fetch("https://apichallenges.herokuapp.com/mirror/request" new URLSearchParams(dataForCalls[index])))
console.log(`sending request ${curReq}...`)
curReq ;
}
// wait until all promises are done or one promise is rejected
await Promise.all(concurrentReq);
console.log(`requests ${curReq - batchSize}-${curReq} done.`)
if(curReq 1 < dataForCalls.length){
// after requests have returned wait for one second
console.log(`[${new Date().toISOString()}] Waiting a second before sending next requests...`)
await waitForMs(1000);
console.log(`[${new Date().toISOString()}] At least one second has gone.`)
}
}
})();
編輯
if通過洗掉并使用以下內容可以獲得更好的解決方案:
// wait at least a second or if the requests take longer than a second wait till they are done
await Promise.all([waitForMs(1000), Promise.all(concurrentReq)]);
顯示代碼片段
// list of items/ data that you might want to use to compose your request
let dataForCalls = [
{ info: 1 },
{ info: 2 },
{ info: 3 },
{ info: 4 },
{ info: 5 },
{ info: 6 },
{ info: 7 },
{ info: 8 },
{ info: 9 },
];
const waitForMs = (ms) => new Promise((resolve, reject) => setTimeout(() => resolve(), ms));
(async () => {
// number of concurrent requests in one batch
const batchSize = 5;
// request counter
let curReq = 0;
// as long as there are items in the list continue to form batches
while (curReq < dataForCalls.length) {
// a batch is either limited by the batch size or it is smaller than the batch size when there are less items required
const end = dataForCalls.length < curReq batchSize ? dataForCalls.length: curReq batchSize;
// we know the number of concurrent request so reserve memory for this
const concurrentReq = new Array(batchSize);
// issue one request for each item in the batch
for (let index = curReq; index < end; index ) {
concurrentReq.push(fetch("https://apichallenges.herokuapp.com/mirror/request" new URLSearchParams(dataForCalls[index])))
console.log(`sending request ${curReq}...`)
curReq ;
}
console.log(`requests ${curReq - batchSize}-${curReq} done.`)
// wait at least a second or if the requests take longer than a second wait till they are done
await Promise.all([waitForMs(1000), Promise.all(concurrentReq)]);
}
})();
如果您不想等到 Promise 完成并且每秒發送一次請求,您只需要等待waitForMs()呼叫并忘記當前正在運行的請求。但是,在這種情況下,您可能在任何時候都有超過 5 個請求,因為請求可能需要超過一秒的時間,但您將被保證(在 的保證范圍內setTimeout())每秒觸發 5 個請求。然而,最后你需要等待所有的 Promise 以保證每個發送的請求都被等待。
// list of items/ data that you might want to use to compose your request
let dataForCalls = [
{ info: 1 },
{ info: 2 },
{ info: 3 },
{ info: 4 },
{ info: 5 },
{ info: 6 },
{ info: 7 },
{ info: 8 },
{ info: 9 },
];
const waitForMs = (ms) => new Promise((resolve, reject) => setTimeout(() => resolve(), ms));
(async () => {
// number of concurrent requests in one batch
const batchSize = 5;
const allRequests = []
// request counter
let curReq = 0;
// as long as there are items in the list continue to form batches
while (curReq < dataForCalls.length) {
// a batch is either limited by the batch size or it is smaller than the batch size when there are less items required
const end = dataForCalls.length < curReq batchSize ? dataForCalls.length : curReq batchSize;
// issue one request for each item in the batch
for (let index = curReq; index < end; index ) {
// create an array with all requests, not just one for each batch
allRequests.push(fetch("https://apichallenges.herokuapp.com/mirror/request" new URLSearchParams(dataForCalls[index])))
console.log(`sending request ${curReq}...`)
curReq ;
}
console.log(`requests ${curReq - batchSize}-${curReq} done.`)
// wait at least a second (see how setTimeout() works in linked Docs)
await waitForMs(1000);
}
// await all requests, not just those of a batch
await Promise.all(allRequests);
console.log(`All requests are done`);
})();
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/513499.html
標籤:javascript异步
