
Linca
@linca
偶然在小红书上刷到一个前端面试题,顺手做了一下。
要求:实现一个带并发限制的异步调度器 Scheduler,保证同时运行的异步任务最多 MAX_LENGTH 个,使得以下程序能正确输出
const timeout = (time) =>
new Promise((resolve) => {
setTimeout(resolve, time);
});
const MAX_LENGTH = 2;
const scheduler = new Scheduler(MAX_LENGTH);
const addTask = (time, order) => {
scheduler
.add(() => {
return timeout(time);
})
.then(() => console.log(order));
};
addTask(1000, "1");
addTask(500, "2");
addTask(300, "3");
addTask(400, "4");
// output: 2 3 1 4
// 一开始,1、2两个任务进入队列
// 500ms时,2完成,输出2,任务3进队
// 800ms时,3完成,输出3,任务4进队
// 1000ms时,1完成,输出1
// 1200ms时,4完成,输出4
感觉还是有点简单,五分钟内肯定是能做出来了。
题解
一开始漏了异常处理的情况,让 gpt 看了眼指了出来
class Scheduler {
running = 0;
pending_tasks: (() => void)[] = [];
queue_len: number;
constructor(queue_len: number) {
this.queue_len = queue_len;
}
async add<T>(promiseCb: () => Promise<T>): Promise<T> {
if (this.running >= this.queue_len) {
await new Promise<void>((resolve) => {
this.pending_tasks.push(resolve);
});
}
this.running++;
try {
return await promiseCb();
} catch (err) {
throw err;
} finally {
const resolve = this.pending_tasks.shift();
if (resolve) {
resolve();
}
this.running--;
}
}
}
const scheduler = new Scheduler(2);
const sleepAndLog = (time: number, ...txt: unknown[]) =>
new Promise((r) => setTimeout(r, time)).then(() => console.log(...txt));
const sleepAndRaiseLog = (time: number, ...txt: unknown[]) =>
new Promise((r) => setTimeout(r, time)).then(() => Promise.reject(...txt));
scheduler.add(() => sleepAndLog(10000, "1"));
scheduler.add(() => sleepAndRaiseLog(5000, "2"));
scheduler.add(() => sleepAndLog(3000, "3"));
scheduler.add(() => sleepAndLog(4000, "4"));