class TaskQueue {
#items = [];
#processing = false;
#cancelled = false;
enqueue(task) { this.#items.push(task); }
dequeue() { return this.#items.shift(); }
peek() { return this.#items[0]; }
isEmpty() { return this.#items.length === 0; }
size() { return this.#items.length; }
cancel() { this.#cancelled = true; }
async processAll(onProgress) {
this.#processing = true;
this.#cancelled = false;
const total = this.size();
let completed = 0;
while (!this.isEmpty() && !this.#cancelled) {
const task = this.dequeue();
await task();
completed++;
onProgress({
completed, total,
percent: Math.round(
(completed / total) * 100
)
});
}
this.#processing = false;
return {
completed, total,
cancelled: this.#cancelled
};
}
}
const queue = new TaskQueue();
// Add 20 images to the queue
selectedImages.forEach(image => {
queue.enqueue(async () => {
const processed = await applyFilterToImage(
image, currentFilter
);
await saveProcessedImage(processed);
});
});
// Process with progress
const result = await queue.processAll(
({ completed, total, percent }) => {
updateProgressBar(percent);
updateStatusText(
`Processing ${completed}/${total}...`
);
}
);
function BatchProcessor({ images, filter }) {
const [progress, setProgress] = useState({
percent: 0, completed: 0, total: 0
});
const [processing, setProcessing] = useState(false);
const queueRef = useRef(null);
const start = async () => {
setProcessing(true);
queueRef.current = new TaskQueue();
images.forEach(img =>
queueRef.current.enqueue(
() => processImage(img, filter)
)
);
await queueRef.current.processAll(setProgress);
setProcessing(false);
};
const cancel = () => queueRef.current?.cancel();
return (
<div>
<ProgressBar percent={progress.percent} />
<p>{progress.completed}/{progress.total}
images processed</p>
{processing ? (
<button onClick={cancel}>Cancel</button>
) : (
<button onClick={start}>
Process All
</button>
)}
</div>
);
}
Queue 20 images, watch the progress bar fill, cancel midway, verify:
| Test | Expected |
|---|---|
| Start processing | Progress bar fills 5%, 10%, 15%... |
| Cancel at 50% | Stops after current image, returns {completed: 10, cancelled: true} |
| Partial results | 10 processed images saved, 10 unprocessed |
| Restart | New queue, fresh progress, starts from beginning |
git switch -c feature/PIXELCRAFT-037-batch-processing
git add src/
git commit -m "Add batch processing with queue, progress, cancel (PIXELCRAFT-037)"
git push origin feature/PIXELCRAFT-037-batch-processing
# PR → Review → Merge → Close ticket ✅
Queues model fairness — first come, first served.
The humble queue pattern scales from your batch processor to global infrastructure.