串行请求
在一些场景下,对于多个ajax请求,需要串行执行,例如
- 某些请求的结果,是后续请求的依赖
- 服务器有并发请求限制
- 某些存在顺序性的用户交互
- 需要请求重试
实现串行请求的核心思路就是通过while循环加await
class Task {
constructor(fn, ...restParam) {
this.fn = fn;
this.restParam = restParam;
}
}
class SerialRequest {
constructor() {
this.queue = [];
this.isRunning = false;
}
add(fn, ...restParam) {
this.queue.push(new Task(fn, ...restParam));
}
async run() {
this.isRunning = true;
while (this.queue.length) {
const task = this.queue.shift();
await task.fn(...task.restParam);
}
this.isRunning = false;
}
clear() {
this.queue = [];
}
}
export default SerialRequest;
并发限制
在很多场景下,需要对同时发出的ajax请求进行限制
- http1.1浏览器对于同一域名下并发数量限制一般为6-8,针对某次任务如果请求并发数过多,会阻塞其他请求
- 调用一些第三方API经常会有QPS限制
- 大文件分片上传/下载
class QPSLimit {
// 单例模式
static instance = null;
static getInstance(...args) {
if (!QPSLimit.instance) {
return new QPSLimit(...args);
}
return QPSLimit.instance;
}
constructor(qps) {
if (QPSLimit.instance) {
return QPSLimit.instance;
}
this.qps = qps; // 限制的qps
this._count = 0; // 当前qps计数
this._taskQueue = []; // 任务队列
QPSLimit.instance = this;
}
// 调用入口,如果qps未满,直接执行,否则加入任务队列
run(caller) {
return new Promise((resolve, reject) => {
const task = this._createTask(caller, resolve, reject);
if (this._count < this.qps) {
task()
} else {
this._taskQueue.push(task)
}
})
}
// 创建任务,任务数量+1,执行完毕后计数-1,如果队列中有任务则继续执行
_createTask(caller, resolve, reject) {
return () => {
this._count++;
caller().then(res => {
resolve(res);
}).catch(err => {
reject(err);
}).finally(() => {
this._count--;
if (this._taskQueue.length) {
this._taskQueue.shift()();
}
})
}
}
}