JavaScript模擬隊列的用法詳解
場景
場景一:
有幾百條數(shù)據(jù)需要傳遞給后端,但是后端每次最多只能接收10條數(shù)據(jù)
場景二:
在彈出第一個彈框并關(guān)閉后再彈第二個彈窗(或者廣告一類的)
我想這些需求大家應(yīng)該都了解過,或者遇到過,我們可能第一反應(yīng)是通過定時器或者Promise來處理,現(xiàn)在我告訴你完全可以通過隊列的方式來處理。我會寫一些示例,如果運用到工作中請根據(jù)自己的需求進行修改即可。
說明
JavaScript 隊列(Queue)是一種先進先出(FIFO)的數(shù)據(jù)結(jié)構(gòu),它用于存儲按順序排列的元素,并支持插入新元素和刪除元素的操作。隊列在計算機科學(xué)中有著廣泛的應(yīng)用,例如在操作系統(tǒng)中實現(xiàn)任務(wù)調(diào)度、在數(shù)據(jù)壓縮中使用哈夫曼編碼等。在JavaScript中,隊列也常用于實現(xiàn)異步編程和控制流程。 JavaScript隊列通常可以通過內(nèi)置的Array對象實現(xiàn),或者使用第三方庫如queue-lib。Array對象提供了push()和shift()方法,可以模擬隊列的入隊和出隊操作。
簡單隊列
我們從下面的模擬隊列中可以看出,我們在執(zhí)行的時候makeRequest(模擬請求)是依次開始執(zhí)行,那么我們想同時執(zhí)行多個請求呢?我們想間隔一段時間在發(fā)送請求呢?那我們接到看下面這個示例。
class RequestQueue {
constructor() {
this.queue = []; // 請求隊列
this.running = 0; // 當前正在運行的請求數(shù)量
}
// 將請求添加到隊列中
enqueue(request) {
this.queue.push(request);
this.run(); // 檢查是否可以運行新的請求
}
// 檢查并運行請求
run() {
if (this.running !== 0 || !this.queue.length) return;
const request = this.queue.shift();
this.execute(request);
this.running++;
}
// 執(zhí)行請求
execute(request) {
request().finally(() => {
this.running--;
if (this.queue.length <= 0) return;
this.run();
});
}
}
// 模擬一個異步請求
function makeRequest(id) {
return new Promise((resolve) => {
console.log(`正在發(fā)送請求 ${id}`);
setTimeout(() => {
console.log(`請求 ${id} 完成`);
resolve(id);
}, 1000);
})
}
// 創(chuàng)建請求隊列并添加10個請求
const queue = new RequestQueue(1, 100);
for (let i = 1; i <= 10; i++) {
queue.enqueue(async () => await makeRequest(i));
};完整隊列
我們從該隊列中可以看出,我們可以去控制自己的并發(fā)量以及間隔時間了,那么我們在考慮下。如果隊列執(zhí)行完成了,我們怎么知道呢?等等。那我們就給他補充完全吧!(這只是我想到的,我沒考慮到的你們也可以自己完善哈)
class RequestQueue {
constructor(limit,delay) {
this.limit = limit; // 最大并發(fā)請求數(shù)
this.delay = delay; // 批次間隔時間(毫秒)
this.queue = []; // 請求隊列
this.running = 0; // 當前正在運行的請求數(shù)量
}
// 將請求添加到隊列中
enqueue(request) {
this.queue.push(request);
this.run(); // 檢查是否可以運行新的請求
}
// 檢查并運行請求
run() {
while (this.running < this.limit && this.queue.length > 0) {
const request = this.queue.shift();
this.execute(request);
this.running++;
}
}
// 執(zhí)行請求
execute(request) {
request().finally(() => {
this.running--;
if (this.queue.length > 0) {
setTimeout(() => {
this.run();
}, this.delay);
}
});
}
}
// 模擬一個異步請求
function makeRequest(id) {
return new Promise((resolve) => {
console.log(`發(fā)起請求 ${id}`);
setTimeout(() => {
console.log(`請求 ${id} 完成`);
resolve(id);
}, 100);
})
}
// 創(chuàng)建請求隊列并添加10,000個請求
const queue = new RequestQueue(5,1000);
for (let i = 1; i <= 20; i++) {
queue.enqueue(async () => await makeRequest(i));
};補充完整隊列
我們在監(jiān)聽隊列是否完成的時候注意一個事,就是Promise在返回的時候一定要在成功的時候才返回。至于原因,你們可以自己去嘗試哈。
class RequestQueue {
timer = null; // 定時器
constructor(limit, delay) {
this.limit = limit; // 最大并發(fā)請求數(shù)
this.delay = delay; // 批次間隔時間(毫秒)
this.queue = []; // 請求隊列
this.running = 0; // 當前正在運行的請求數(shù)量
}
// 將請求添加到隊列中
enqueue(request) {
this.queue.push(request);
this.run(); // 檢查是否可以運行新的請求
}
// 檢查并運行請求
run() {
while (this.running < this.limit && this.queue.length > 0) {
const request = this.queue.shift();
this.execute(request);
this.running++;
}
}
// 執(zhí)行請求
execute(request) {
request().finally(() => {
this.running--;
if (this.queue.length > 0) {
setTimeout(() => {
this.run();
}, this.delay);
}
});
}
// 監(jiān)聽隊列是否完成
isQueueEmpty() {
return new Promise((resolve, reject) => {
this.timer = setInterval(() => {
if (this.queue.length === 0 && this.running === 0) {
clearInterval(this.timer);
this.timer = null;
resolve(true);
}
}, 1000);
})
}
}
// 模擬一個異步請求
function makeRequest(id) {
return new Promise((resolve) => {
console.log(`發(fā)起請求 ${id}`);
setTimeout(() => {
console.log(`請求 ${id} 完成`);
resolve(id);
}, 100);
})
}
// 創(chuàng)建請求隊列并添加10,000個請求
const queue = new RequestQueue(5, 1000);
for (let i = 1; i <= 20; i++) {
queue.enqueue(async () => await makeRequest(i));
};
// 執(zhí)行完成返回ture
queue.isQueueEmpty().then(res=>{
console.log(res);
})總結(jié)
以上就是JavaScript模擬隊列的基礎(chǔ)寫法用法,大家也可以根據(jù)你們的需要進行修改和完善。
到此這篇關(guān)于JavaScript模擬隊列的用法詳解的文章就介紹到這了,更多相關(guān)JavaScript模擬隊列內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

