前端請求并發(fā)和請求覆蓋的解決方法
頁面太多接口并發(fā)請求會出現(xiàn)什么問題?
- 服務(wù)器壓力會變大:大量的并發(fā)請求會導致服務(wù)器的負載增加,從而影響服務(wù)器的性能和穩(wěn)定性。
- 網(wǎng)絡(luò)擁堵:一個域名最多有 6 個并發(fā)請求(不同瀏覽器可能限制不一樣),超過 6 個并發(fā)請求會導致網(wǎng)絡(luò)擁堵,從而影響頁面的加載速度和用戶體驗。
- 響應(yīng)延遲:由于服務(wù)器需要處理大量的并發(fā)請求,所以響應(yīng)延遲會增加,從而影響頁面的響應(yīng)速度和用戶體驗。
解決方式也有很多,比如:
- 負載均衡:分發(fā)請求到多個服務(wù)器上
- 聚合接口:將多個接口合并成一個接口,減少接口的并發(fā)請求
- CDN 內(nèi)容分發(fā):通過不同的域名進行請求,從而突破瀏覽器單個域名并發(fā)請求限制
以上都是基于運維和后端的角度,那么前端如何解決呢?
并發(fā)請求
思路:設(shè)置并發(fā)請求限制,用隊列存放請求,每次請求會先判斷是否超出設(shè)置的最大并發(fā)請求數(shù),當請求完成后,從隊列中取出下一個請求,直到隊列中的請求全部完成。
export class RequestQueue {
constructor(concurrency = 6) {
this.concurrency = concurrency; // 設(shè)置最大并發(fā)數(shù),默認為6
this.queue = []; // 存放請求的隊列
this.current = 0; // 當前正在執(zhí)行的請求數(shù)
}
// 處理隊列中的請求(出隊)
dequeue() {
while (this.current < this.concurrency && this.queue.length) {
this.current++;
// 從隊列中取出下一個請求并執(zhí)行
const requestPromiseFactory = this.queue.shift();
requestPromiseFactory()
.then(() => {
// 成功的請求邏輯
})
.catch((error) => {
// 失敗
console.log(error);
})
.finally(() => {
this.current--;
this.dequeue();
});
}
}
// 添加請求到隊列中(入隊)
enqueue(requestPromiseFactory) {
this.queue.push(requestPromiseFactory);
this.dequeue();
}
}
代碼解釋:
- 構(gòu)造函數(shù) (constructor):初始化了并發(fā)數(shù) (concurrency)、請求隊列 (queue) 和當前正在執(zhí)行的請求數(shù)量 (current)。
- 入隊方法 (enqueue):將請求添加到隊列中,并立即調(diào)用 dequeue 方法開始處理隊列。
- 出隊方法 (dequeue):從隊列中取出請求并執(zhí)行。如果請求成功,執(zhí)行成功邏輯;如果請求失敗,捕獲錯誤并記錄。無論成功或失敗,最終都會調(diào)用 finally 塊來減少當前正在執(zhí)行的請求數(shù)量,并繼續(xù)處理下一個請求。
實際使用
const requestQueue = new RequestQueue(6); // 創(chuàng)建一個并發(fā)數(shù)為6的請求隊列
// 模擬一個異步函數(shù)
sleep(fn) {
return new Promise(resolve => {
setTimeout(() => {
resolve(fn);
}, 2000);
});
},
// 生成測試請求
const queue = [...Array(20)].map((_, i) => () =>
this.sleep(
axios
.get('/api/test' + i)
.then(r => console.log(i, '成功'))
.catch(e => console.log('失敗', i))
)
);
// 添加請求到隊列中
for (let i = 0; i < queue.length; i++) {
requestQueue.enqueue(queue[i]);
}
請求覆蓋
場景:先后有A、B兩個請求,A請求還未返回,B請求已經(jīng)發(fā)起,并且B請求的結(jié)果比A先返回,那么A請求就會覆蓋B請求的結(jié)果,正常要的結(jié)果是B的結(jié)果覆蓋掉A請求的結(jié)果
可以用隊列來維護請求的順序,按照隊列的順序發(fā)起請求,但這有種“殺雞用牛刀”的感覺,因為我們完全可以取消之前的請求,用最新的請求結(jié)果來賦值
可以通過以下方式解決請求覆蓋的問題:
- 時序控制:定全局標識,比如數(shù)字,依次累加,每個請求響應(yīng)中判斷當前的標識是否 ≥ 全局標識,是則返回結(jié)果,否則不返回結(jié)果。
- 取消舊請求:發(fā)送新請求時判斷是否有舊請求,有則取消舊請求,然后再發(fā)送新請求。
方法一:時序控制
let requestId = 0; // 全局標識
// 發(fā)送請求
function sendRequest() {
const currentRequestId = ++requestId; // 遞增全局標識
// 發(fā)起請求
axios.get('/api/data')
.then(response => {
// 判斷當前請求是否是最新的請求(如果有新的請求那么requestId在新的請求會+1,比當前這個方法的curentRequestId的要大)
if (currentRequestId >= requestId) {
// 處理響應(yīng)數(shù)據(jù)
console.log(response.data);
}
})
.catch(error => {
// 處理錯誤
console.error(error);
});
}
方法二:取消舊請求
// 通過axios的cancelToken來取消請求
let cancelToken; // 取消請求的令牌
// 發(fā)送請求
function sendRequest() {
// 取消舊請求
if (cancelToken) {
cancelToken.cancel();
}
// 創(chuàng)建新的取消請求的令牌
cancelToken = axios.CancelToken.source();
// 發(fā)起請求
axios.get('/api/data', {
cancelToken: cancelToken.token
})
.then(response => {
// 處理響應(yīng)數(shù)據(jù)
console.log(response.data);
})
.catch(error => {
// 處理錯誤
console.error(error);
});
}
// 自定義的取消請求函數(shù)
let lastCancel = null;
let cancelable = (req, callback) => {
let cb = callback;
req.then(res => {
cb && cb(res);
})
let cancel = () => {
cb = null;
}
return cancel;
}
let sendRequest() {
lastCancel && lastCancel();
lastCancel = cancelable(axios.get('/api/data'), res => {
console.log(res);
})
}
到此這篇關(guān)于前端請求并發(fā)和請求覆蓋的解決方法的文章就介紹到這了,更多相關(guān)前端請求并發(fā)和請求覆蓋內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Typescript中infer關(guān)鍵字的使用小結(jié)
infer是TypeScript中條件類型的一個關(guān)鍵字,主要用于在條件類型中進行類型推斷,下面就來詳細的介紹一下Typescript infer關(guān)鍵字的使用,感興趣的可以了解一下2026-01-01
原生js操作checkbox用document.getElementById實現(xiàn)
js操作checkbox本人建議用document.getElementById(checkbox_id).checked不推薦使用jquery操作checkbox,感興趣的朋友不要錯過2013-10-10
解決layer彈出層的內(nèi)容頁點擊按鈕跳轉(zhuǎn)到新的頁面問題
今天小編就為大家分享一篇解決layer彈出層的內(nèi)容頁點擊按鈕跳轉(zhuǎn)到新的頁面問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-09-09
swiperjs實現(xiàn)導航與tab頁的聯(lián)動
這篇文章主要為大家詳細介紹了swiperjs實現(xiàn)導航與tab頁的聯(lián)動,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-12-12

