題目
假設有這么一個場景:現(xiàn)在有20個異步請求需要發(fā)送,但是由于HTTP客戶端一般對同一個服務器的并發(fā)連接個數(shù)都是有限制的,比如chrome瀏覽器同一時刻最大并發(fā)數(shù)是6。
實現(xiàn)一個并發(fā)請求函數(shù)concurrencyRequest(urls, maxNum),要求如下:
- 要求最大并發(fā)數(shù) maxNum
- 每當有一個請求返回,就留下一個空位,可以增加新的請求
- 所有請求完成后,結(jié)果按照 urls 里面的順序依次打出(發(fā)送請求的函數(shù)可以直接使用fetch即可)
測試代碼
const urls = [];
for (let i = 1; i <= 20; i++) {
urls.push(`https://jsonplaceholder.typicode.com/todos/${i}`);
}
concurrencyRequest(urls, 3).then(res => {
console.log(res);
})
復制代碼
具體實現(xiàn)
// 并發(fā)請求函數(shù)
const concurrencyRequest = (urls, maxNum) => {
// 因為測試代碼調(diào)用concurrencyRequest后需要返回一個Promise
return new Promise((resolve) => {
// urls的長度為0時,results就沒有值,此時應該返回空數(shù)組
if (urls.length === 0) {
resolve([]);
return;
}
const results = [];
let index = 0; // 下一個請求的下標
let count = 0; // 當前請求完成的數(shù)量
// 發(fā)送請求
async function request() {
if (index === urls.length) return;
const i = index; // 保存序號,使result和urls相對應
const url = urls[index];
index++;
console.log(url);
try {// 請求成功
const res = await fetch(url);
// resp 加入到results
results[i] = res;
} catch (err) {// 請求失敗
// err 加入到results
results[i] = err;
} finally {// 請求失敗或成功都補一個新的請求進來
// 請求完成計數(shù)器
count++;
// 判斷是否所有的請求都已完成
if (count === urls.length) {
console.log('完成了');
resolve(results);
}
//
request();
}
}
// maxNum大于urls的長度時,應該取的是urls的長度,否則則是取maxNum
const times = Math.min(maxNum, urls.length);
// 開啟第一次批量調(diào)用
for(let i = 0; i < times; i++) {
request();
}
})
}
復制代碼
思路
- 首先按照每次只能并發(fā)3個請求的要求,這里就對應A、B、C,當其中有一個請求完之后就會再從urls里面再取出一個進行請求,這樣依次類推,直到urls里面的20個請求都執(zhí)行完才終止請求。
- urls的長度為0時,results就沒有值,此時應該返回空數(shù)組
- maxNum大于urls的長度時,應該取的是urls的長度,否則則是取maxNum
- 需要單獨定義一個count計數(shù)器來判斷是否已全部請求完成;
- 因為沒有考慮請求是否請求成功,所以請求成功或報錯都應把結(jié)果保存在results集合中
- results中的順序需和urls中的保持一致