Non Blocking Channel Operations in TypeScript

Basic sends and receives on channels are blocking in many concurrent programming models. However, we can implement non-blocking operations using a similar pattern in TypeScript with Promises and async/await.

async function main() {
    const messages = new Promise<string>((resolve) => {
        // Simulating a channel
    });
    const signals = new Promise<boolean>((resolve) => {
        // Simulating a channel
    });

    // Here's a non-blocking receive. If a value is
    // available on `messages` then it will be logged.
    // If not, it will immediately log "no message received".
    try {
        const msg = await Promise.race([
            messages,
            Promise.reject("no message")
        ]);
        console.log("received message", msg);
    } catch (error) {
        console.log("no message received");
    }

    // A non-blocking send works similarly. Here `msg`
    // cannot be sent to the `messages` promise, because
    // it has no resolver. Therefore, the catch block is executed.
    const msg = "hi";
    try {
        await Promise.race([
            new Promise<void>((resolve) => {
                // Simulating sending a message
                resolve();
            }),
            Promise.reject("no send")
        ]);
        console.log("sent message", msg);
    } catch (error) {
        console.log("no message sent");
    }

    // We can use multiple promises with `Promise.race`
    // to implement a multi-way non-blocking select.
    // Here we attempt non-blocking receives on both
    // `messages` and `signals`.
    try {
        const result = await Promise.race([
            messages.then(msg => ({ type: 'message', value: msg })),
            signals.then(sig => ({ type: 'signal', value: sig })),
            Promise.reject("no activity")
        ]);
        if (result.type === 'message') {
            console.log("received message", result.value);
        } else {
            console.log("received signal", result.value);
        }
    } catch (error) {
        console.log("no activity");
    }
}

main();

To run the program:

$ ts-node non-blocking-operations.ts
no message received
no message sent
no activity

This TypeScript code demonstrates how to implement non-blocking operations using Promises and async/await. While it doesn’t directly correspond to channels in other languages, it achieves similar functionality in an idiomatic TypeScript way.

The Promise.race function is used to simulate the behavior of a select statement with a default case. It allows us to attempt an operation and immediately fall back to a default action if the operation doesn’t complete instantly.

Remember that this is a simplified example and real-world scenarios might require more robust error handling and resource management.