Skip to content

Promise Utilities

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.

Before diving into the Queue class, let’s look at some helpful utility functions for working with promises:

A function to pause execution for a specified duration:

import { wait } from 'dill-pixel';
// 'wait' is an alias for delay
await wait(2);

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)); // true
console.log(isPromise(value2)); // false
// Useful in type guards
function processValue(value: unknown) {
if (isPromise(value)) {
// TypeScript now knows value is a Promise
value.then((result) => console.log(result));
}
}

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 function
const queue = createQueue(
fetch('api/data'),
() => loadTexture('sprite.png'),
async () => await playAnimation(),
);
// Or create directly
const queue2 = new Queue([fetch('api/data'), () => loadTexture('sprite.png')]);

Control the execution flow of your promises:

const queue = new Queue([() => fetch('/api/data1'), () => fetch('/api/data2'), () => fetch('/api/data3')]);
// Start execution
queue.start();
// Check progress (returns a number between 0 and 1)
console.log(queue.progress); // e.g., 0.33 after first promise completes
// Pause execution
queue.pause();
// Resume execution
queue.resume();
// Cancel execution
queue.cancel();

The Queue class provides a progress property that returns a number between 0 and 1, representing the completion percentage:

src/scenes/MyScene.ts
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!');
}
}

Track the results of executed promises:

const queue = new Queue([() => fetchUserData(), () => fetchGameState(), () => fetchLeaderboard()]);
queue.start();
// Later...
const results = queue.results; // Array of resolved values
const queue = new Queue([() => fetch('/api/user'), () => fetch('/api/preferences'), () => fetch('/api/stats')]);
queue.start();
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();
const queue = new Queue([
async () => processChunk(data.slice(0, 100)),
async () => processChunk(data.slice(100, 200)),
async () => processChunk(data.slice(200, 300)),
]);
queue.start();
  1. 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;
    }
    },
    ]);
  2. Dynamic Queue Management:

    const queue = new Queue();
    // Add tasks dynamically
    for (const url of urls) {
    queue.add(async () => {
    const response = await fetch(url);
    return response.json();
    });
    }
    queue.start();
// Less efficient: Creating new queues frequently
function update() {
const queue = new Queue([task1, task2]); // Don't do this
queue.start();
}
// More efficient: Reuse queues
class 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();
}
}
  1. Combine with other utilities:

    import { Queue, wait } from 'dill-pixel';
    const queue = new Queue([
    async () => {
    console.log('Starting');
    await wait(1);
    console.log('Done');
    },
    ]);
  2. 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')]);
  3. Handle cleanup:

    const queue = new Queue([
    /* tasks */
    ]);
    // Later when needed
    queue.cancel(); // Stop current execution
    queue.clear(); // Remove all tasks