前端如何实现并发请求数量控制?

2023-11-29 16:30:28 浏览数 (1)

并发请求数量过大,会在短时间内发送大量的网络请求,并且占用大量的系统资源,可能会造成接口阻塞,浏览器卡死现象。怎么才能降低并发请求数量呢?

一、并发控制核心逻辑

==========

1、创建一个ListPromise


类主要为了限制同时执行的任务数量来控制并发量

代码语言:javascript复制
class ListPromise {

}

2、constructor


构造函数接受一个参数max,用以设置最大并发数,并初始化了一些属性

  • _max:最大并发数
  • _count:当前任务执行数
  • _taskQueue:任务队列
  • instance:当前类实例
代码语言:javascript复制
class ListPromise {
      constructor(max) {
				this._max = max;
				this._count = 0
				this._taskQueue = [];
				// 当前实例
				this.instance = null;
			}
}

3、run


主入口。添加任务到队列并返回Promise,接受一个参数caller,用于执行异步任务。

  • 通过_createTask创建一个任务,并判断当前任务数是否超过最大并发数
代码语言:txt复制
*   超过:把任务放入到任务队列
*   没超过:执行任务,调用task()返回
代码语言:javascript复制
	run(caller) {
				// 主入口
				// 输入:外部添加的请求
				// 输出:队列中的任务队列
				return new Promise((resolve, reject) => {
					// 创建处理任务
					const task = this._createTask(caller, resolve, reject)
					// 当前任务数量是否达到上限
					if (this._count >= this._max) {
						this._taskQueue.push(task)
					} else {
						task()
					}
				})
			}

4、_createTask


创建任务,返回一个任务函数,这就可以理解为什么在run中通过this._createTask创建的任务可以直接调用。 任务函数会执行caller函数,根据结果去调用reslove()或者reject。 在直接结束时当前任务数减1,通过this._taskQueue.length判断当前队列中是否还有待执行的任务。如果有则取出并执行。

代码语言:javascript复制
_createTask(caller, resolve, reject) {
				return () => {
					caller().then(res => {
						resolve(res)
					}).catch(err => {
						reject(err)
					}).finally(() => {
						this._count--;
						if (this._taskQueue.length) {
							const task = this._taskQueue.shift();
							task()
						}
					})
					this._count  ;
				}

			}

5、获取ListPromise单例实例


如果当前实例不存在,则生成一个实例,否则返回当前实例。

代码语言:javascript复制
static getInstance(max) {
				if (!this.instance) {
					this.instance = new ListPromise(max)
				}
				return this.instance;
			}

6、ListPromise核心代码


代码语言:javascript复制
class ListPromise {
			constructor(max) {
				this._max = max;
				this._count = 0
				this._taskQueue = [];
				// 当前实例
				this.instance = null;
			}
			run(caller) {
				// 主入口
				// 输入:外部添加的请求
				// 输出:队列中的任务队列
				return new Promise((resolve, reject) => {
					// 创建处理任务
					const task = this._createTask(caller, resolve, reject)
					// 当前任务数量是否达到上限
					if (this._count >= this._max) {
						this._taskQueue.push(task)
					} else {
						task()
					}
				})
			}
			_createTask(caller, resolve, reject) {
				return () => {
					caller().then(res => {
						resolve(res)
					}).catch(err => {
						reject(err)
					}).finally(() => {
						this._count--;
						if (this._taskQueue.length) {
							const task = this._taskQueue.shift();
							task()
						}
					})
					this._count  ;
				}

			}
			static getInstance(max) {
				if (!this.instance) {
					this.instance = new ListPromise(max)
				}
				return this.instance;
			}

		}

二、具体使用

======

1、创建一个ListPromise实例,并设置最大并发量


代码语言:javascript复制
const listPromise = ListPromise.getInstance(2); // 设置最大并发数为 2

2、模拟异步操作


通过setTimeout模拟一个异步任务,并且声明testFunction返回一个Promise

代码语言:javascript复制
	function delay(ms) {
			return new Promise((resolve) => setTimeout(resolve, ms));
		}
	function testFunction() {
			return delay(1000); // 模拟一个异步函数
		}

3、添加任务队列


通过listPromise.run(testFunction)添加到任务队列中,testFunction是一个异步函数,返回值是Promise,可以通过then 以及catch处理成功和失败时的回调。

4、具体使用时核心代码


代码语言:javascript复制
		// 示例用法
		const listPromise = ListPromise.getInstance(2); // 设置最大并发数为 2

		function delay(ms) {
			return new Promise((resolve) => setTimeout(resolve, ms));
		}

		function testFunction() {
			return delay(1000); // 模拟一个异步函数
		}

		listPromise.run(testFunction)
			.then(() => console.log('Task 1 completed'))
			.catch((err) => console.error('Task 1 failed:', err));

		listPromise.run(testFunction)
			.then(() => console.log('Task 2 completed'))
			.catch((err) => console.error('Task 2 failed:', err));

		listPromise.run(testFunction)
			.then(() => console.log('Task 3 completed'))
			.catch((err) => console.error('Task 3 failed:', err));
		listPromise.run(testFunction)
			.then(() => console.log('Task 4 completed'))
			.catch((err) => console.error('Task 4 failed:', err));
		listPromise.run(testFunction)
			.then(() => console.log('Task 5 completed'))
			.catch((err) => console.error('Task 5 failed:', err));
		listPromise.run(testFunction)
			.then(() => console.log('Task 6 completed'))
			.catch((err) => console.error('Task 6 failed:', err));
		listPromise.run(testFunction)
			.then(() => console.log('Task 7 completed'))
			.catch((err) => console.error('Task 7 failed:', err));
		listPromise.run(testFunction)
			.then(() => console.log('Task 8 completed'))
			.catch((err) => console.error('Task 8 failed:', err));

三、源码

====

代码语言:javascript复制
	class ListPromise {
			constructor(max) {
				this._max = max;
				this._count = 0
				this._taskQueue = [];
				// 当前实例
				this.instance = null;
			}
			run(caller) {
				// 主入口
				// 输入:外部添加的请求
				// 输出:队列中的任务队列
				return new Promise((resolve, reject) => {
					// 创建处理任务
					const task = this._createTask(caller, resolve, reject)
					// 当前任务数量是否达到上限
					if (this._count >= this._max) {
						this._taskQueue.push(task)
					} else {
						task()
					}
				})

			}
			_createTask(caller, resolve, reject) {
				return () => {
					caller().then(res => {
						resolve(res)
					}).catch(err => {
						reject(err)
					}).finally(() => {
						this._count--;
						if (this._taskQueue.length) {
							const task = this._taskQueue.shift();
							task()
						}
					})
					this._count  ;
				}

			}
			static getInstance(max) {
				if (!this.instance) {
					this.instance = new ListPromise(max)
				}
				return this.instance;
			}

		}
		// 示例用法
		const listPromise = ListPromise.getInstance(2); // 设置最大并发数为 2

		function delay(ms) {
			return new Promise((resolve) => setTimeout(resolve, ms));
		}

		function testFunction() {
			return delay(1000); // 模拟一个异步函数
		}

		listPromise.run(testFunction)
			.then(() => console.log('Task 1 completed'))
			.catch((err) => console.error('Task 1 failed:', err));

		listPromise.run(testFunction)
			.then(() => console.log('Task 2 completed'))
			.catch((err) => console.error('Task 2 failed:', err));

		listPromise.run(testFunction)
			.then(() => console.log('Task 3 completed'))
			.catch((err) => console.error('Task 3 failed:', err));
		listPromise.run(testFunction)
			.then(() => console.log('Task 4 completed'))
			.catch((err) => console.error('Task 4 failed:', err));
		listPromise.run(testFunction)
			.then(() => console.log('Task 5 completed'))
			.catch((err) => console.error('Task 5 failed:', err));
		listPromise.run(testFunction)
			.then(() => console.log('Task 6 completed'))
			.catch((err) => console.error('Task 6 failed:', err));
		listPromise.run(testFunction)
			.then(() => console.log('Task 7 completed'))
			.catch((err) => console.error('Task 7 failed:', err));
		listPromise.run(testFunction)
			.then(() => console.log('Task 8 completed'))
			.catch((err) => console.error('Task 8 failed:', err));

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞