我原本以为JavaScript是不能写队列的,最近发现JavaScript是可以模拟队列的,并且花样还挺多。
场景
场景一:
有几百条数据需要传递给后端,但是后端每次最多只能接收10条数据
场景二:
在弹出第一个弹框并关闭后再弹第二个弹窗(或者广告一类的)
我想这些需求大家应该都了解过,或者遇到过,我们可能第一反应是通过定时器或者Promise来处理,现在我告诉你完全可以通过队列的方式来处理。我会写一些示例,如果运用到工作中请根据自己的需求进行修改即可。
说明
JavaScript 队列(Queue)是一种先进先出(FIFO)的数据结构,它用于存储按顺序排列的元素,并支持插入新元素和删除元素的操作。队列在计算机科学中有着广泛的应用,例如在操作系统中实现任务调度、在数据压缩中使用哈夫曼编码等。在JavaScript中,队列也常用于实现异步编程和控制流程。 JavaScript队列通常可以通过内置的Array对象实现,或者使用第三方库如queue-lib。Array对象提供了push()和shift()方法,可以模拟队列的入队和出队操作。
简单队列
我们从下面的模拟队列中可以看出,我们在执行的时候makeRequest(模拟请求)是依次开始执行,那么我们想同时执行多个请求呢?我们想间隔一段时间在发送请求呢?那我们接到看下面这个示例。
javascript
class RequestQueue {
constructor() {
this.queue = []; // 请求队列
this.running = 0; // 当前正在运行的请求数量
}
// 将请求添加到队列中
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++;
}
// 执行请求
execute(request) {
request().finally(() => {
this.running--;
if (this.queue.length <= 0) return;
this.run();
});
}
}
// 模拟一个异步请求
function makeRequest(id) {
return new Promise((resolve) => {
console.log(`正在发送请求 ${id}`);
setTimeout(() => {
console.log(`请求 ${id} 完成`);
resolve(id);
}, 1000);
})
}
// 创建请求队列并添加10个请求
const queue = new RequestQueue(1, 100);
for (let i = 1; i <= 10; i++) {
queue.enqueue(async () => await makeRequest(i));
};
完整队列
我们从该队列中可以看出,我们可以去控制自己的并发量以及间隔时间了,那么我们在考虑下。如果队列执行完成了,我们怎么知道呢?等等。那我们就给他补充完全吧!(这只是我想到的,我没考虑到的你们也可以自己完善哈)
javascript
class RequestQueue {
constructor(limit,delay) {
this.limit = limit; // 最大并发请求数
this.delay = delay; // 批次间隔时间(毫秒)
this.queue = []; // 请求队列
this.running = 0; // 当前正在运行的请求数量
}
// 将请求添加到队列中
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++;
}
}
// 执行请求
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(`发起请求 ${id}`);
setTimeout(() => {
console.log(`请求 ${id} 完成`);
resolve(id);
}, 100);
})
}
// 创建请求队列并添加10,000个请求
const queue = new RequestQueue(5,1000);
for (let i = 1; i <= 20; i++) {
queue.enqueue(async () => await makeRequest(i));
};
补充完整队列
我们在监听队列是否完成的时候注意一个事,就是Promise在返回的时候一定要在成功的时候才返回。至于原因,你们可以自己去尝试哈。
javascript
class RequestQueue {
timer = null; // 定时器
constructor(limit, delay) {
this.limit = limit; // 最大并发请求数
this.delay = delay; // 批次间隔时间(毫秒)
this.queue = []; // 请求队列
this.running = 0; // 当前正在运行的请求数量
}
// 将请求添加到队列中
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++;
}
}
// 执行请求
execute(request) {
request().finally(() => {
this.running--;
if (this.queue.length > 0) {
setTimeout(() => {
this.run();
}, this.delay);
}
});
}
// 监听队列是否完成
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(`发起请求 ${id}`);
setTimeout(() => {
console.log(`请求 ${id} 完成`);
resolve(id);
}, 100);
})
}
// 创建请求队列并添加10,000个请求
const queue = new RequestQueue(5, 1000);
for (let i = 1; i <= 20; i++) {
queue.enqueue(async () => await makeRequest(i));
};
// 执行完成返回ture
queue.isQueueEmpty().then(res=>{
console.log(res);
})
总结
以上就是JavaScript模拟队列的基础写法用法,大家也可以根据你们的需要进行修改和完善。赶紧打开vscode内卷起来吧!哈哈哈