编程 在JavaScript中实现队列

2024-11-19 01:38:36 +0800 CST views 486

原来 JavaScript 也可以写队列

我原本以为 JavaScript 不能写队列,但最近发现 JavaScript 可以模拟队列,并且有很多不同的实现方式。

场景

场景一

有几百条数据需要传递给后端,但后端每次最多只能接收 10 条数据。

场景二

在弹出第一个弹框并关闭后再弹第二个弹窗(或者广告)。

这些需求大家应该都了解过,或者遇到过。我们可能第一反应是通过定时器或者 Promise 来处理,但其实完全可以通过队列的方式来处理。下面我会写一些示例,大家可以根据自己的需求进行修改。

说明

JavaScript 队列(Queue)是一种先进先出(FIFO)的数据结构,用于存储按顺序排列的元素,并支持插入新元素和删除元素的操作。队列在计算机科学中有着广泛的应用,例如在操作系统中实现任务调度、在数据压缩中使用哈夫曼编码等。在 JavaScript 中,队列也常用于实现异步编程和控制流程。

JavaScript 队列通常可以通过内置的 Array 对象实现,或者使用第三方库如 queue-lib。Array 对象提供了 push()shift() 方法,可以模拟队列的入队和出队操作。

简单队列

下面是一个简单的请求队列示例:

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();
for (let i = 1; i <= 10; i++) {
    queue.enqueue(async () => await makeRequest(i));
}

完整队列

我们可以控制并发量以及请求间隔时间。下面是一个更完整的实现:

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));
}

补充完整队列

我们可以增加一个方法来监听队列是否完成:

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) => {
            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));
}

// 执行完成返回 true
queue.isQueueEmpty().then(res => {
    console.log(res);
});

总结

以上就是 JavaScript 模拟队列的基础写法和用法,大家可以根据需要进行修改和完善。赶紧打开 VSCode 内卷起来吧!

推荐文章

用 Rust 构建一个 WebSocket 服务器
2024-11-19 10:08:22 +0800 CST
H5端向App端通信(Uniapp 必会)
2025-02-20 10:32:26 +0800 CST
Go语言中实现RSA加密与解密
2024-11-18 01:49:30 +0800 CST
如何实现虚拟滚动
2024-11-18 20:50:47 +0800 CST
Vue中的表单处理有哪几种方式?
2024-11-18 01:32:42 +0800 CST
使用 Git 制作升级包
2024-11-19 02:19:48 +0800 CST
css模拟了MacBook的外观
2024-11-18 14:07:40 +0800 CST
CSS Grid 和 Flexbox 的主要区别
2024-11-18 23:09:50 +0800 CST
Vue 3 路由守卫详解与实战
2024-11-17 04:39:17 +0800 CST
Python中何时应该使用异常处理
2024-11-19 01:16:28 +0800 CST
Dropzone.js实现文件拖放上传功能
2024-11-18 18:28:02 +0800 CST
Git 常用命令详解
2024-11-18 16:57:24 +0800 CST
如何在 Linux 系统上安装字体
2025-02-27 09:23:03 +0800 CST
Vue3中如何使用计算属性?
2024-11-18 10:18:12 +0800 CST
html一个包含iPhoneX和MacBook模拟器
2024-11-19 08:03:47 +0800 CST
乐观锁和悲观锁,如何区分?
2024-11-19 09:36:53 +0800 CST
实用MySQL函数
2024-11-19 03:00:12 +0800 CST
使用 node-ssh 实现自动化部署
2024-11-18 20:06:21 +0800 CST
OpenCV 检测与跟踪移动物体
2024-11-18 15:27:01 +0800 CST
一个收银台的HTML
2025-01-17 16:15:32 +0800 CST
浅谈CSRF攻击
2024-11-18 09:45:14 +0800 CST
JavaScript 流程控制
2024-11-19 05:14:38 +0800 CST
如何在Rust中使用UUID?
2024-11-19 06:10:59 +0800 CST
Nginx负载均衡详解
2024-11-17 07:43:48 +0800 CST
程序员茄子在线接单