JS 并发调度器

浏览器的并发连接数量是有限的,对于 chrome,一般是 6 个。那么对于瞬时大量请求发送的场景,如果不加管控,那么有些排队靠后的请求,很可能在等待到浏览器调度前,就耗尽自己的时间限制,从而自我取消。针对这个问题,可以设计实现一个并发调度器,将并发请求“缓存”起来,控制并发数,从而避免请求在浏览器排队时超时。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const LimitPromise = function (concurrent = 5) {
this.concurrent = concurrent;
this.pendingRequests = 0;
this.queue = [];
};

LimitPromise.prototype.dequeue = function () {
while (this.pendingRequests < this.concurrent && this.queue.length) {
this.pendingRequests++;
const { task, resolve, reject } = this.queue.shift();
task()
.then(resolve, reject)
.finally(() => {
this.pendingRequests--;
this.dequeue();
});
}
};

LimitPromise.prototype.run = function (task) {
return new Promise((resolve, reject) => {
this.queue.push({
task,
resolve,
reject,
});
this.dequeue();
});
};

使用时,假设有一个异步任务 task:

1
2
3
4
5
// 全局常量
const limitPromise = new LimitPromise()

// 发送请求时
limitPromise.run(task)

当一个异步任务加入并发队列后,按照代码,其并不会直接触发,而是尝试执行一次出列。在出列时,按照并发数限制依次取出队列中的任务执行,当一个任务执行后,不论失败,均再次执行一次出列,并将标记当前并发数的变量 pendingRequests 减一。从而实现了并发调度。

封面来自 SAWARATSUKI kawaiilogos,该作者还没上传 JS 的 logo,所以用 nodeJS 的冒充一下。