JS的promise可用于封装各类异步调用场景,但多数接口都有访问qps的限制,要求实现一个ES6 class (或ES5函数类),该类可以接受并行执行promise的上限M作为构造参数,通过提供一个enqueue方法来接收promise生成函数,并确保线程执行中的promise数量始终不超过M,调用样例参考:
最优雅的方式
class Atom {
exeCount;
maxLen;
que;
constructor(maxLenNum) {
this.exeCount = 0;
this.maxLen = maxLenNum;
this.que = [];
}
add(p) {
this.que.push(p);
if (this.exeCount < this.maxLen) {
this.exe();
}
}
exe() {
let ps = this.que.shift();
this.exeCount++;
let outTimePromise = new Promise((res, rej) => {
setTimeout(() => {
rej("outTime");
}, 2000);
});
Promise.race([ps(), outTimePromise]).then(
(res) => {
this.next();
},
(rej) => {
console.log(rej || "error");
this.next();
}
);
}
next() {
this.exeCount--;
if (this.que.length > 0 && this.exeCount < this.maxLen) {
this.exe();
}
}
}
function sleep(delay, index, err) {
return new Promise((resolve, reject) => {
if (err) {
reject();
return;
}
setTimeout(() => {
console.log(index);
resolve();
}, delay);
});
}
let atom = new Atom(2);
atom.add(async () => await sleep(1000, 1));
atom.add(async () => await sleep(500, 2));
atom.add(async () => await sleep(300, 3));
atom.add(async () => await sleep(400, 4));
atom.add(async () => await sleep(3000, 5));
atom.add(async () => await sleep(400, 6, 1));
//2,3,1,4,error,outTime
var instance = new PromiseHandler(3);
var promiseList = [1,2,3,4].map(i => {
return () => new Promise(resolve => setTimeout(() => {
console.log(i);
resolve();
}, 1000 * i));
});
// 注意这里是返回一个promise,确保promise的实际执行完全由生成器控制
var extraPromise = () => new Promise(resolve => setTimeout(() => {
console.log('new');
resolve();
}, 1000));
instance.enqueue(promiseList);
instance.enqueue(extraPromise);
// console.log
第1s:1
第2s:2
第3s:3
第3s:new
第5s: 4
题解:
class PromiseHandler {
//待执行队列
queue;
//限定长度的正在执行队列
executeQueue;
//最大并行数量
maxNum;
constructor(num) {
this.maxNum = num;
this.queue = [];
this.executeQueue = [];
}
enqueue = function (newPromiseFnArray) {
this.queue = this.queue.concat(newPromiseFnArray);
let lenOfQueue = this.executeQueue.length;
//如果当前执行队列已经满了,则不再做入队操作
if (lenOfQueue >= this.maxNum) {
return;
}
this.enExecuteQueue();
this.fn();
};
fn = function () {
let count = 0;
for (let i = 0; i < this.executeQueue.length; i++) {
this.executeQueue[i]()
.then(
(res) => {
count++;
},
(rej) => {
count++;
}
)
.catch()
.finally(() => {
//并发数达到限制时,说明所有的promise都执行结束了
if (count === this.executeQueue.length) {
//promise都执行完了,可以清空当前的执行队列了
this.executeQueue = [];
//从待执行队列王当期执行队列中入队
this.enExecuteQueue();
//如果当前执行队列还有内容则执行队列中剩下的内容
this.executeQueue.length > 0 && this.fn();
}
});
}
};
enExecuteQueue = function () {
while (this.executeQueue.length < this.maxNum && this.queue.length > 0) {
this.executeQueue.push(this.queue.shift());
}
};
}
var instance = new PromiseHandler(3);
var promiseList = [1, 2, 3, 4].map((i) => {
return () =>
new Promise((resolve) =>
setTimeout(() => {
console.log(i);
resolve();
}, 1000 * i)
);
});
// 注意这里是返回一个promise,确保promise的实际执行完全由生成器控制
var extraPromise = () =>
new Promise((resolve) =>
setTimeout(() => {
console.log("new");
resolve();
}, 1000)
);
instance.enqueue(promiseList);
instance.enqueue(extraPromise);
写法二
class Scheduler {
len = 2;
schedulerQueue = [];
tmpQueue = [];
running = 0;
add(promiseCreator) {
if (this.schedulerQueue.length >= this.len) {
this.tmpQueue.push(promiseCreator);
return;
}
this.schedulerQueue.push(promiseCreator);
this.ex();
}
ex() {
while (this.schedulerQueue.length > 0 && this.running < this.len) {
const p = this.schedulerQueue.shift();
this.running++;
p().then(() => {
this.running--;
if (this.tmpQueue.length > 0) {
this.schedulerQueue.push(this.tmpQueue.shift());
}
this.ex();
});
}
}
}```