如何用JavaScript实现一个并发任务控制的任务调度器
Author:zhoulujun Date:
还是推荐查看react scheduler的经典实现……
调度器(Scheduler )
调度器是一种可以控制任务执行顺序的工具,通常用于异步任务的处理。比如:
requestAnimationFrame
requestIdleCallback
setTimeout
MessageChannel
微任务
MutationObserver
Promise
在Java里面,Timer 和 ScheduledExecutor 都仅能提供基于开始时间与重复间隔的任务调度,不能胜任更加复杂的调度需求。但Spring3.0以后自带的task,即:spring schedule,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多。
而前端,React Scheduler 是 react 提供的一个可以独立使用的包,可以单独使用 任务调度器。
https://github.com/zhoulujun/mini-react/blob/master/docs/schedule/哪些API适合用于任务调度.md
Scheduler 是 React 提供的调度器,它内部暴露unstable_scheduleCallback(priorityLevel, callback, options)方法给我们调度任务,其中priorityLevel是调度的优先级,callback 是我们的任务,optoins 里面可以通过指定delay延迟执行我们的任务。
Scheduler 支持任务按优先级排序执行,优先级通过过期时间体现,比如 ImmediatePriority 对应的过期时间是 -1毫秒,需要立即执行。
var ImmediatePriority = 1; // 对应的过期时间:IMMEDIATE_PRIORITY_TIMEOUT -1毫秒 立即执行 var UserBlockingPriority = 2; // 对应的过期时间:USER_BLOCKING_PRIORITY_TIMEOUT 250毫秒 后过期 var NormalPriority = 3; // 对应的过期时间:NORMAL_PRIORITY_TIMEOUT 5000毫秒 后过期 var LowPriority = 4; // 对应的过期时间:LOW_PRIORITY_TIMEOUT 10000毫秒 后过期 var IdlePriority = 5; // 对应的过期时间:IDLE_PRIORITY_TIMEOUT maxSigned31BitInt永不过期
具体参看:https://github.com/zhoulujun/mini-react/blob/master/docs/schedule/scheduler用法详解.md
设计调度器
在 JavaScript 中,我们可以使用 Promise 对象和 async/await 函数来实现调度器。
class TaskScheduler {
constructor(concurrencyLimit) {
this.concurrencyLimit = concurrencyLimit; // 最大并发数
this.queue = []; // 任务队列
this.runningCount = 0; // 当前正在执行的任务数量
}
async runTask(blockId) {
// 模拟异步请求数据的操作
await fetchBlockData(blockId);
console.log(`Fetched data for blockId: ${blockId}`);
}
async scheduleTasks(blockIds) {
// 将所有任务加入队列
this.queue.push(...blockIds);
while (this.queue.length > 0) {
// 如果当前正在执行的任务数量小于并发数限制,执行新任务
if (this.runningCount < this.concurrencyLimit) {
const blockId = this.queue.shift();
if (blockId) {
this.runningCount++;
this.runTask(blockId).finally(() => {
this.runningCount--;
this.scheduleTasks([]);
});
}
}
// 等待一段时间后再次检查队列
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
}
// 模拟异步请求数据的函数
function fetchBlockData(blockId) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`Data for blockId ${blockId}`);
}, Math.random() * 2000); // 模拟耗时 0 到 2 秒的请求
});
}
// 测试
const blockIds = ['1', '2', '3', '4'];
const scheduler = new TaskScheduler(2); // 最多同时执行两个任务
scheduler.scheduleTasks(blockIds);
这样的代码,AI写的贼溜了,比如通义千问
class TaskScheduler {
private queue: (() => Promise<void>)[] = [];
private runningTasks: (() => Promise<void>)[] = [];
private maxConcurrency: number;
constructor(maxConcurrency: number) {
this.maxConcurrency = maxConcurrency;
}
// 添加任务到队列
schedule(task: () => Promise<void>): void {
this.queue.push(task);
this.runNext();
}
// 开始执行队列中的下一个任务
private async runNext(): Promise<void> {
// 如果当前运行的任务少于最大并发数,并且队列中还有任务
while (this.runningTasks.length < this.maxConcurrency && this.queue.length > 0) {
const task = this.queue.shift();
if (task) {
this.runningTasks.push(task);
}
}
// 等待所有当前运行的任务完成
if (this.runningTasks.length > 0) {
await Promise.all(this.runningTasks.map(task => task()));
}
// 移除已完成的任务
this.runningTasks = [];
// 检查是否有更多任务可执行
this.runNext();
}
}
// 示例用法
const scheduler = new TaskScheduler(2); // 控制同时并发2个任务
// 假设我们有一些异步任务
const task1 = async () => {
console.log('Starting task1');
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('Finished task1');
};
const task2 = async () => {
console.log('Starting task2');
await new Promise(resolve => setTimeout(resolve, 500));
console.log('Finished task2');
};
const task3 = async () => {
console.log('Starting task3');
await new Promise(resolve => setTimeout(resolve, 1500));
console.log('Finished task3');
};
const task4 = async () => {
console.log('Starting task4');
await new Promise(resolve => setTimeout(resolve, 700));
console.log('Finished task4');
};
scheduler.schedule(task1);
scheduler.schedule(task2);
scheduler.schedule(task3);
scheduler.schedule(task4);
转载本站文章《如何用JavaScript实现一个并发任务控制的任务调度器》,
请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/js/2021_1230_9184.html