如何用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