如何实现支持任务推送与并发控制的JavaScript异步任务运行器?
Concurrent Task Runner with Async Support
Got it, let's build this robust task runner that handles concurrent execution limits and supports async tasks like user input waits or API calls. Here's a complete implementation with clear explanations:
Full Implementation Code
class Runner { constructor(concurrent) { this.taskQueue = []; this.currentRunning = 0; this.concurrentLimit = concurrent; } push(task) { // Add the new task to our waiting queue this.taskQueue.push(task); // Immediately try to start the next available task this._runNext(); } async _runNext() { // Keep processing tasks as long as we have slots and waiting tasks while (this.currentRunning < this.concurrentLimit && this.taskQueue.length > 0) { const task = this.taskQueue.shift(); this.currentRunning++; try { // Wait for the async task to complete (works for promises, async functions) await task(); } catch (error) { // Optional: Handle task failures here, or let the task itself manage errors console.error(`Task failed:`, error); } finally { // Free up a slot once the task finishes (success or failure) this.currentRunning--; // Trigger the next task in the queue this._runNext(); } } } }
Key Details Explained
- Concurrent Limit Enforcement: We track
currentRunningto make sure we never exceed the specified number of active tasks at any time. - Queue Management: New tasks are added to
taskQueuewhen pushed, and the private_runNextmethod handles dequeuing and executing tasks as slots open up. - Async Task Compatibility: Using
await task()ensures we properly wait for all types of async operations—whether it's an API call, asetTimeout, or a promise waiting for user input. - Error Resilience: The
try/catchblock ensures a failed task won't crash the entire runner; we log the error (or handle it as needed) and keep processing the queue.
Example Usage
Let's test it with simulated async tasks to see how the concurrency works:
// Create a runner that allows 2 concurrent tasks const runner = new Runner(2); // Helper to create mock async tasks (mimics API calls or user actions) const createMockTask = (taskId, delay) => { return async () => { console.log(`Starting task ${taskId}`); await new Promise(resolve => setTimeout(resolve, delay)); console.log(`Finished task ${taskId}`); }; }; // Push tasks to the runner runner.push(createMockTask(1, 2000)); runner.push(createMockTask(2, 1000)); runner.push(createMockTask(3, 1500)); runner.push(createMockTask(4, 500));
In this test, tasks 1 and 2 start right away. When task 2 finishes after 1 second, task 3 kicks off immediately. Task 4 waits until either task 1 or 3 completes before starting—all while sticking to the 2-task concurrent limit.
内容的提问来源于stack exchange,提问作者Roy
相关产品推荐
相关产品推荐

