JavaScript Task Scheduler
You need to build a robust task scheduler in JavaScript. This scheduler will allow users to add tasks that need to be executed at specific times or after a certain delay. This is a fundamental component for many applications, from simple reminders to complex background processing.
Problem Description
The goal is to create a TaskScheduler class that can manage and execute tasks. The scheduler should support adding tasks with different scheduling mechanisms:
- Immediate execution: Tasks that should run as soon as possible.
- Delayed execution: Tasks that should run after a specified delay in milliseconds.
- Scheduled execution: Tasks that should run at a specific future
Date. - Recurring tasks: Tasks that should run repeatedly at a fixed interval.
The scheduler should also provide functionality to cancel scheduled tasks before they are executed.
Key Requirements:
-
addTask(taskFn, options)Method:taskFn: A function representing the task to be executed.options(optional): An object to configure the task's scheduling.delay: Number of milliseconds to wait before executing the task (for delayed execution).scheduleAt: ADateobject specifying the exact time to execute the task.interval: Number of milliseconds for recurring tasks. Ifintervalis provided, the task will run repeatedly everyintervalmilliseconds. The task will be scheduled to run for the first time afterdelayorscheduleAtif those are also provided. If onlyintervalis provided, it will run immediately and then repeat.runOnce: Iftrueandintervalis also provided, the task will only run once after the initial delay/schedule. This is to prevent unintended infinite loops ifintervalis set but the user only wants a single delayed execution after a potential first interval.
-
cancelTask(taskId)Method:- Accepts a unique
taskIdreturned byaddTask. - Removes the task from the scheduler, preventing it from executing.
- Accepts a unique
-
Task Identification: The
addTaskmethod should return a unique identifier for each added task, which will be used for cancellation. -
Error Handling: Tasks should be wrapped in
try...catchblocks to prevent a single failing task from crashing the entire scheduler. Log errors to the console.
Expected Behavior:
- Tasks scheduled with
delayshould execute after the specified milliseconds. - Tasks scheduled with
scheduleAtshould execute precisely at the specifiedDate(within reasonable system timing limits). - Recurring tasks with
intervalshould execute repeatedly at the given interval. - Cancellation should stop a task from running, whether it's pending, scheduled, or currently running (though stopping a task mid-execution is not a requirement, cancellation only affects future executions).
Edge Cases:
- Adding tasks with no options (immediate execution).
- Canceling a task that has already executed.
- Canceling a task that was never added.
- Tasks that throw errors during execution.
- Tasks with
intervalandrunOnce: true.
Examples
Example 1: Delayed Execution
const scheduler = new TaskScheduler();
const taskId = scheduler.addTask(() => {
console.log("Task 1 executed after 2 seconds.");
}, { delay: 2000 });
// Expected Output (after 2 seconds):
// Task 1 executed after 2 seconds.
Example 2: Scheduled Execution and Cancellation
const scheduler = new TaskScheduler();
const now = new Date();
const futureTime = new Date(now.getTime() + 5000); // 5 seconds from now
const taskId = scheduler.addTask(() => {
console.log("Task 2 executed at the scheduled time.");
}, { scheduleAt: futureTime });
console.log(`Task 2 scheduled for: ${futureTime.toLocaleTimeString()}`);
// Cancel the task before it executes
setTimeout(() => {
scheduler.cancelTask(taskId);
console.log(`Task 2 with ID ${taskId} has been canceled.`);
}, 3000); // Cancel after 3 seconds
// Expected Output:
// Task 2 scheduled for: [time 5 seconds from now]
// Task 2 with ID [some ID] has been canceled.
// (Task 2 executed at the scheduled time. will NOT be printed)
Example 3: Recurring Task
const scheduler = new TaskScheduler();
const taskId = scheduler.addTask(() => {
console.log(`Recurring task executed at: ${new Date().toLocaleTimeString()}`);
}, { interval: 3000 }); // Execute every 3 seconds
// Stop the recurring task after 10 seconds
setTimeout(() => {
scheduler.cancelTask(taskId);
console.log(`Recurring task with ID ${taskId} has been stopped.`);
}, 10000);
// Expected Output (will appear multiple times):
// Recurring task executed at: [time]
// Recurring task executed at: [time + 3s]
// Recurring task executed at: [time + 6s]
// Recurring task executed at: [time + 9s]
// Recurring task with ID [some ID] has been stopped.
Example 4: Task with Delay and Interval, then runOnce
const scheduler = new TaskScheduler();
const taskId = scheduler.addTask(() => {
console.log(`This task should run once after a delay of 1 second.`);
}, { delay: 1000, interval: 5000, runOnce: true });
// Expected Output (after 1 second):
// This task should run once after a delay of 1 second.
// (The task will NOT repeat because runOnce is true)
Constraints
- The
TaskSchedulerclass should be implemented using standard JavaScript features. - No external libraries are allowed for the core scheduling logic.
- The
taskIdreturned byaddTaskmust be unique for each task instance. - The scheduler should be reasonably efficient; avoid busy-waiting.
Notes
- Consider using
setTimeoutandsetIntervalfor implementing delayed and recurring tasks. - For scheduled tasks (
scheduleAt), you'll need to calculate the delay required to reach thescheduleAttime. - Think about how to manage the state of tasks (pending, running, canceled).
- Ensure your task IDs are truly unique. A simple counter or a UUID generator could be considered.
- The
Dateobject in JavaScript can be tricky. Pay attention to time zones and howgetTime()works.