Waitgroups in TypeScript

Our example demonstrates how to wait for multiple asynchronous operations to finish using Promises in TypeScript. This is similar to the concept of WaitGroups in other languages.

import { setTimeout } from 'timers/promises';

// This is the function we'll run in every asynchronous operation
async function worker(id: number): Promise<void> {
    console.log(`Worker ${id} starting`);

    // Sleep to simulate an expensive task
    await setTimeout(1000);
    console.log(`Worker ${id} done`);
}

async function main() {
    // This array will hold all our worker Promises
    const workers: Promise<void>[] = [];

    // Launch several asynchronous operations and add their Promises to the array
    for (let i = 1; i <= 5; i++) {
        workers.push(worker(i));
    }

    // Wait for all workers to complete
    await Promise.all(workers);

    // Note that this approach automatically propagates errors from workers.
    // If error handling is needed, consider using Promise.allSettled() instead.
}

main().catch(console.error);

To run the program:

$ ts-node waitgroups.ts
Worker 1 starting
Worker 2 starting
Worker 3 starting
Worker 4 starting
Worker 5 starting
Worker 1 done
Worker 2 done
Worker 3 done
Worker 4 done
Worker 5 done

In this TypeScript version, we use Promises to manage asynchronous operations. The worker function is defined as an async function that simulates an expensive task using setTimeout.

In the main function, we create an array of Promises, each corresponding to a worker. We then use Promise.all() to wait for all workers to complete. This is analogous to the WaitGroup.Wait() in the original example.

Note that the order of workers starting up and finishing is likely to be different for each invocation, just like in the original example.

Unlike the original example, error propagation is straightforward with Promises. If any of the workers throws an error, it will be caught in the main().catch() block. For more advanced error handling, you could use Promise.allSettled() instead of Promise.all().

TypeScript and JavaScript don’t have built-in constructs exactly equivalent to goroutines, but asynchronous functions and Promises provide similar capabilities for managing concurrent operations.