BatchScheduler is an elegant and powerful task scheduling library for JavaScript/TypeScript applications. It provides a simple yet flexible API for managing and executing tasks in batches with support for:
- Task prioritization
- Batching contexts
- Task cancellation
- Error handling
- Async/await support
- Zero dependencies
You can install the package via npm:
npm install @avatijs/batch-scheduler
Or using yarn:
yarn add @avatijs/batch-scheduler
import { BatchScheduler } from '@avatijs/batch-scheduler';
// Get the scheduler instance
const scheduler = BatchScheduler.getInstance();
// Schedule a simple task
scheduler.schedule(() => {
console.log('Task executed');
});
// Schedule a high-priority task
scheduler.schedule(() => {
console.log('High-priority task');
}, { priority: 10 });
// Schedule an async task
scheduler.schedule(async () => {
await someAsyncOperation();
console.log('Async task completed');
});
Use batching to group multiple tasks together:
import { batchUpdates } from '@avatijs/batch-scheduler';
batchUpdates(() => {
// All tasks scheduled here will be executed together
scheduler.schedule(() => console.log('Task 1'));
scheduler.schedule(() => console.log('Task 2'));
scheduler.schedule(() => console.log('Task 3'));
});
Tasks can be cancelled before execution using cancellation tokens:
const token = scheduler.createCancellationToken();
scheduler.schedule(() => {
console.log('This task may be cancelled');
}, { cancellationToken: token });
// Cancel the task before it executes
token.cancel();
Handle task errors gracefully:
scheduler.schedule(() => {
throw new Error('Task failed');
}, {
onError: (error) => {
console.error('Handled task error:', error);
},
});
Tasks with higher priority values are executed first:
scheduler.schedule(task1, { priority: 1 }); // Executed third
scheduler.schedule(task2, { priority: 5 }); // Executed second
scheduler.schedule(task3, { priority: 10 }); // Executed first
For fine-grained control over batching:
scheduler.startBatch();
// Schedule multiple tasks
scheduler.schedule(task1);
scheduler.schedule(task2);
// Other operations...
scheduler.endBatch(); // Tasks are executed
Force immediate processing of all pending tasks:
scheduler.flush();
Properly shutdown the scheduler when needed:
scheduler.shutdown();
// Good: Group related UI updates
batchUpdates(() => {
scheduler.schedule(() => updateHeader());
scheduler.schedule(() => updateSidebar());
scheduler.schedule(() => updateFooter());
});
// Good: Proper error handling
scheduler.schedule(
async () => {
await fetchUserData();
},
{
onError: (error) => {
logger.error('Failed to fetch user data:', error);
showErrorNotification();
}
}
);
// Good: Critical updates get higher priority
scheduler.schedule(
() => updateCriticalMetrics(),
{ priority: 10 }
);
scheduler.schedule(
() => updateNonCriticalUI(),
{ priority: 1 }
);
// Good: Proper cleanup on component unmount
class Component {
private token = scheduler.createCancellationToken();
scheduleTask() {
scheduler.schedule(
() => this.updateData(),
{ cancellationToken: this.token }
);
}
cleanup() {
this.token.cancel();
}
}
// Bad: Creating multiple instances
const scheduler1 = new BatchScheduler(); // ❌
const scheduler2 = new BatchScheduler(); // ❌
// Good: Use singleton instance
const scheduler = BatchScheduler.getInstance(); // ✅
// Bad: Nesting batch operations
batchUpdates(() => {
scheduler.schedule(() => task1());
batchUpdates(() => { // ❌ Nested batch
scheduler.schedule(() => task2());
});
});
// Good: Flatten batch operations
batchUpdates(() => {
scheduler.schedule(() => task1());
scheduler.schedule(() => task2());
});
// Bad: Long-running synchronous task
scheduler.schedule(() => {
while(heavyComputation()) { } // ❌ Blocks the thread
});
// Good: Break up or make async
scheduler.schedule(async () => {
const chunks = splitIntoChunks(data);
for (const chunk of chunks) {
await processChunk(chunk);
}
});
// Bad: Not handling cancellation
scheduler.schedule(async () => {
const data = await fetchData(); // ❌ Continues even if cancelled
processData(data);
});
// Good: Check cancellation status
const token = scheduler.createCancellationToken();
scheduler.schedule(async () => {
if (token.isCancelled) return;
const data = await fetchData();
if (token.isCancelled) return;
processData(data);
}, { cancellationToken: token });
// Bad: Flushing within batch
batchUpdates(() => {
scheduler.schedule(() => task1());
scheduler.flush(); // ❌ Throws error
});
// Good: Flush outside batch
batchUpdates(() => {
scheduler.schedule(() => task1());
});
scheduler.flush(); // ✅
- Task Size: Keep tasks small and focused
- Error Handling: Always provide error handlers for critical tasks
- Priorities: Use priorities sparingly and meaningfully
- Cancellation: Implement cancellation for long-running or resource-intensive tasks
- Batching: Group related tasks that should be executed together
- Async Operations: Prefer async operations for I/O or long-running tasks
- Cleanup: Always clean up by cancelling pending tasks when appropriate
-
getInstance(): BatchScheduler
- Returns the singleton instance of BatchScheduler
-
schedule(task: TaskFunction, options?: TaskOptions): void
- Schedules a task for execution
- Options include
priority
,onError
, andcancellationToken
-
startBatch(): void
- Begins a new batching context
-
endBatch(): void
- Ends the current batching context
-
flush(): void
- Immediately processes all pending tasks
-
shutdown(): void
- Cancels all pending tasks and prevents new scheduling
-
createCancellationToken(): CancellationToken
- Creates a new cancellation token
-
batchUpdates<T>(fn: () => T): T
- Executes a function within a batching context
Please see CHANGELOG for more information what has changed recently.
I welcome contributions from developers of all experience levels. If you have an idea, found a bug, or want to improve something, I encourage you to get involved!
- Read Contributing Guide for details on how to get started.
- Fork the repository and make your changes.
- Submit a pull request, and we’ll review it as soon as possible.
Avati is open-source and distributed under the MIT License.