原来JavaScript也可以写队列

我原本以为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内卷起来吧!哈哈哈

相关推荐
deli00712 分钟前
1 个汉字算几个 token?实测中英文 prompt 与代码的编码差异
前端
无限聚核18 分钟前
抖音 certificate.prepare 之后怎么验券?和美团 msconsume 差在哪,无限聚核
前端·微信小程序
2603_9658966228 分钟前
Grid 网格布局|CSS 二维页面排版体系
前端·css
有味道的男人43 分钟前
搜好货平台关键词商品搜索接口:分页容错与商品数据轻量化提取方案
服务器·前端·javascript
lovingsoft1 小时前
Chrome Lighthouse 详解
前端·chrome
Qlly2 小时前
全栈工程师怎么接需求?从一句「加个功能」聊到能开发、能验收
前端·后端
马可家的菠萝2 小时前
你的微信“文件传输助手”,是不是已经成了第二个网盘?
前端·后端·架构
略略略啦2 小时前
Vibe Coding 基于Spec DD和TDD的实践指南
前端
shmily麻瓜小菜鸡2 小时前
前端实现图片与PDF文字识别敏感信息打码方案
前端·pdf·状态模式
打工仔折腾 AI2 小时前
LangChain 工具调用实战:从 Tool 定义到 Agent 执行链路拆解
java·前端·人工智能·后端·python·langchain·ai agent 实战