Promise Utilities
Overview
Promise utilities provide powerful tools for managing asynchronous operations in your game. The main feature is the Queue
class, which allows you to execute promises sequentially with control over their execution flow.
Promise Utility Functions
Before diving into the Queue class, let’s look at some helpful utility functions for working with promises:
wait
A function to pause execution for a specified duration:
import { wait } from 'dill-pixel';
// 'wait' is an alias for delayawait wait(2);
isPromise
A type guard function to check if a value is a Promise:
import { isPromise } from 'dill-pixel';
const value1 = Promise.resolve();const value2 = 42;
console.log(isPromise(value1)); // trueconsole.log(isPromise(value2)); // false
// Useful in type guardsfunction processValue(value: unknown) { if (isPromise(value)) { // TypeScript now knows value is a Promise value.then((result) => console.log(result)); }}
Queue Class
The Queue class provides a way to manage and execute a sequence of promises with control over their execution:
import { Queue, createQueue } from 'dill-pixel';
// Create a queue using the factory functionconst queue = createQueue( fetch('api/data'), () => loadTexture('sprite.png'), async () => await playAnimation(),);
// Or create directlyconst queue2 = new Queue([fetch('api/data'), () => loadTexture('sprite.png')]);
Queue Control
Control the execution flow of your promises:
const queue = new Queue([() => fetch('/api/data1'), () => fetch('/api/data2'), () => fetch('/api/data3')]);
// Start executionqueue.start();
// Check progress (returns a number between 0 and 1)console.log(queue.progress); // e.g., 0.33 after first promise completes
// Pause executionqueue.pause();
// Resume executionqueue.resume();
// Cancel executionqueue.cancel();
Tracking Progress
The Queue class provides a progress
property that returns a number between 0 and 1, representing the completion percentage:
import { Scene, Queue } from 'dill-pixel';
export default class MyScene extends Scene { private _queueComplete = false; private queue = new Queue([ async () => { await fetch('/api/data1'); }, async () => { await fetch('/api/data2'); }, async () => { await fetch('/api/data3'); }, ]);
async start() { this.queue.start(); }
async update(dt: number) { if (!this._queueComplete) { this._showQueueProgress(); if (this.queue.progress === 1) { this._queueComplete = true; this._onQueueComplete(); } } }
private _showQueueProgress() { console.log(`Progress: ${Math.round(this.queue.progress * 100)}%`); }
private _onQueueComplete() { console.log('Queue complete!'); }}
Accessing Results
Track the results of executed promises:
const queue = new Queue([() => fetchUserData(), () => fetchGameState(), () => fetchLeaderboard()]);
queue.start();
// Later...const results = queue.results; // Array of resolved values
Common Use Cases
Sequential API Calls
const queue = new Queue([() => fetch('/api/user'), () => fetch('/api/preferences'), () => fetch('/api/stats')]);
queue.start();
Timed Operations
const queue = new Queue([ async () => { console.log('Start'); await wait(1); console.log('After 1 second'); }, async () => { await wait(2); console.log('After 2 more seconds'); },]);
queue.start();
Data Processing
const queue = new Queue([ async () => processChunk(data.slice(0, 100)), async () => processChunk(data.slice(100, 200)), async () => processChunk(data.slice(200, 300)),]);
queue.start();
Best Practices
-
Error Handling:
const queue = new Queue([async () => {try {const response = await fetch('/api/data');return await response.json();} catch (error) {console.error('Failed to fetch:', error);return null;}},]); -
Dynamic Queue Management:
const queue = new Queue();// Add tasks dynamicallyfor (const url of urls) {queue.add(async () => {const response = await fetch(url);return response.json();});}queue.start();
Performance Considerations
Efficient Usage
// Less efficient: Creating new queues frequentlyfunction update() { const queue = new Queue([task1, task2]); // Don't do this queue.start();}
// More efficient: Reuse queuesclass TaskManager { private queue = new Queue();
runTasks(tasks: (() => Promise<void>)[]) { this.queue.cancel(); // Clear previous tasks tasks.forEach((task) => this.queue.add(task)); this.queue.start(); }}
Tips and Tricks
-
Combine with other utilities:
import { Queue, wait } from 'dill-pixel';const queue = new Queue([async () => {console.log('Starting');await wait(1);console.log('Done');},]); -
Create task factories:
function createFetchTask(url: string) {return async () => {const response = await fetch(url);return response.json();};}const queue = new Queue([createFetchTask('/api/data1'), createFetchTask('/api/data2')]); -
Handle cleanup:
const queue = new Queue([/* tasks */]);// Later when neededqueue.cancel(); // Stop current executionqueue.clear(); // Remove all tasks