tiny-essentials
Version:
Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.
222 lines (161 loc) • 8.1 kB
Markdown
`TinyPromiseQueue` is a queue system designed to manage and execute asynchronous tasks in a sequential, one-at-a-time order. Tasks are executed in the order they are added to the queue, with support for optional delays ⏳, task cancellation ❌, and task reordering 🔄.
---
- **`
- **`
- **`
- **`
---
Returns whether the queue is currently processing a task.
- `boolean`: `true` if the queue is processing a task, otherwise `false`.
---
Returns the index of a task in the queue by its ID.
- `id` (`string`): The ID of the task to locate.
- `number`: The index of the task in the queue, or `-1` if not found.
---
Returns a list of IDs for all tasks currently in the queue.
- `Array<{ index: number, id: string }>`: An array of task IDs and their corresponding indices.
---
Reorders a task in the queue from one index to another.
- `fromIndex` (`number`): The current index of the task to move.
- `toIndex` (`number`): The index where the task should be placed.
- `void`: This method does not return anything.
---
Adds a new async task to the queue and ensures it runs in order after previous tasks. Optionally, a delay can be added before the task is executed.
If the task is canceled before execution, it will be rejected with the message:
**"The function was canceled on TinyPromiseQueue."**
- `task` (`Function`): A function that returns a `Promise` to be executed sequentially.
- `delay` (`number|null`): Optional delay (in ms) before the task is executed.
- `id` (`string`): Optional ID to identify the task in the queue.
#### Returns:
- `Promise<any>`: A promise that resolves or rejects with the result of the task once it's processed.
---
### `enqueuePoint(task, id)` 🪢
Adds an async task to a parallel group in the queue. All tasks added with `enqueuePoint` before the next `enqueue` will be executed **simultaneously**, but only after all previous tasks in the queue have completed.
These grouped tasks share a "concurrent checkpoint" and will run using `Promise.all`. Each task resolves or rejects independently.
If a task is canceled before execution, it will be rejected with the message:
**"The function was canceled on TinyPromiseQueue."**
#### Parameters:
- `task` (`Function`): A function that returns a `Promise` to be executed sequentially.
- `id` (`string`): Optional ID to identify the task in the queue.
#### Returns:
- `Promise<any>`: A promise that resolves or rejects with the result of the task once it's processed.
---
### `cancelTask(id)` ❌
Cancels a scheduled delay and removes the task from the queue. Adds the ID to a blacklist so the task is skipped if already being processed.
#### Parameters:
- `id` (`string`): The ID of the task to cancel.
#### Returns:
- `boolean`: `true` if a delay was cancelled and the task was removed, otherwise `false`.
---
## Usage Example 💻
```js
import { TinyPromiseQueue } from './TinyPromiseQueue';
const queue = new TinyPromiseQueue();
// Helper function to create simple tasks with logs
function createTask(name, duration = 500) {
return () => new Promise((resolve) => {
console.log(`Started task: ${name}`);
setTimeout(() => {
console.log(`Finished task: ${name}`);
resolve(name);
}, duration);
});
}
// Enqueue 3 tasks
queue.enqueue(createTask('A'), 100, 'taskA');
queue.enqueue(createTask('B'), 0, 'taskB');
queue.enqueue(createTask('C'), 0, 'taskC');
// Wait for 50ms and cancel taskB
setTimeout(() => {
const success = queue.cancelTask('taskB');
console.log('Canceled taskB:', success); // true if cancelled
}, 50);
// List the remaining IDs in the queue
setTimeout(() => {
const ids = queue.getQueuedIds();
console.log('Queued IDs:', ids);
}, 60);
```
```js
import { TinyPromiseQueue } from './TinyPromiseQueue';
const queue = new TinyPromiseQueue();
await new Promise((resolve) => {
// Task generator with color-coded logs
function createTask(name, duration = 500) {
return () =>
new Promise((resolve) => {
console.log(`\x1b[34m[STARTED]\x1b[0m \x1b[36m${name}\x1b[0m`);
setTimeout(() => {
console.log(`\x1b[32m[FINISHED]\x1b[0m \x1b[36m${name}\x1b[0m`);
resolve(name);
}, duration);
});
}
// Function to simulate a parallel group of enqueues
const parallelEnqueueGroup = (groupName, delayStart = 0) => {
const count = Math.floor(Math.random() * (15 - 1 + 1) + 1);
for (let i = 1; i <= count; i++) {
const taskName = `${groupName}-${i}`;
queue.enqueue(createTask(taskName, 300 + i * 50), delayStart, taskName);
}
};
// Main enqueue block
queue.enqueue(createTask('Init-1', 400), 50, 'init-1');
queue.enqueue(createTask('Init-2', 400), 0, 'init-2');
// Simulate enqueues from other contexts "in parallel"
parallelEnqueueGroup('Alpha', 80); // Starts after 80ms
parallelEnqueueGroup('Beta', 120); // Starts after 120ms
parallelEnqueueGroup('Gamma', 250); // Starts after 250ms
parallelEnqueueGroup('Delta', 180); // Starts after 180ms
parallelEnqueueGroup('Epsilon', 300); // Starts after 300ms
parallelEnqueueGroup('Zeta', 160); // Starts after 160ms
parallelEnqueueGroup('Eta', 90); // Starts after 90ms
parallelEnqueueGroup('Theta', 220); // Starts after 220ms
parallelEnqueueGroup('Iota', 140); // Starts after 140ms
parallelEnqueueGroup('Kappa', 400); // Starts after 400ms
parallelEnqueueGroup('Lambda', 190); // Starts after 190ms
parallelEnqueueGroup('Mu', 260); // Starts after 260ms
parallelEnqueueGroup('Nu', 110); // Starts after 110ms
parallelEnqueueGroup('Xi', 330); // Starts after 330ms
parallelEnqueueGroup('Omicron', 170); // Starts after 170ms
parallelEnqueueGroup('Pi', 280); // Starts after 280ms
parallelEnqueueGroup('Rho', 70); // Starts after 70ms
parallelEnqueueGroup('Sigma', 360); // Starts after 360ms
parallelEnqueueGroup('Tau', 130); // Starts after 130ms
parallelEnqueueGroup('Upsilon', 240); // Starts after 240ms
parallelEnqueueGroup('Phi', 310); // Starts after 310ms
parallelEnqueueGroup('Chi', 100); // Starts after 100ms
parallelEnqueueGroup('Psi', 200); // Starts after 200ms
parallelEnqueueGroup('Omega', 50); // Starts after 50ms
// Final task to confirm everything executed
setTimeout(() => {
queue.enqueue(createTask('Finalizer', 500), 0, 'finalizer').then(() => {
console.log('\x1b[35m[QUEUE COMPLETE]\x1b[0m All tasks have been processed.');
resolve();
});
}, 250);
});
```
1. **Task Creation**: Tasks are created with a name and an optional duration (in ms). The task logs its start and finish times 🕰️.
2. **Task Execution**: Tasks are enqueued one at a time, ensuring they run in the order they were added 🔁.
3. **Cancellation**: After 50ms, taskB is canceled, demonstrating the ability to remove a task from the queue ❌.
4. **Remaining Tasks**: The remaining tasks in the queue are logged after 60ms 📊.
---
## Conclusion 🎯
`TinyPromiseQueue` provides a simple and effective way to manage a sequence of asynchronous tasks. With its support for delays ⏳, task cancellation ❌, and reordering 🔄, it allows for efficient control over task execution in JavaScript.