We use cookies (including Google cookies) to personalize ads and analyze traffic. By continuing to use our site, you accept our Privacy Policy.

Design Cancellable Function

Difficulty: Hard


Problem Description

Design a function cancellable that accepts a generator object and returns an array containing a cancel function and a promise. This function should handle the generator's promises, allow cancellation, and manage errors accordingly.


Key Insights

  • The generator yields promises and must be able to handle their resolution or rejection.
  • If the cancel function is invoked, the generator should throw a "Cancelled" error.
  • If the generator finishes execution without cancellation, the promise resolves with the returned value.
  • If the generator throws an error during execution, the promise should reject with that error.
  • The function must manage the state of the generator and the promises efficiently.

Space and Time Complexity

Time Complexity: O(n), where n is the number of yielded promises. Space Complexity: O(n), for storing the state of the generator and any pending promises.


Solution

The solution involves creating a wrapper around the generator function that maintains its state and handles the promises it yields. The cancellable function will:

  1. Start executing the generator and handle its yielded promises.
  2. Provide a cancel function that, when called, will throw a "Cancelled" error back to the generator.
  3. Return a promise that resolves or rejects based on the generator's behavior—either the final return value or any errors thrown.

The primary data structures used are the generator object and promises. The algorithm employs async/await to manage the flow of promise resolutions and error handling effectively.


Code Solutions

function cancellable(generator) {
    let cancel;
    const promise = new Promise((resolve, reject) => {
        const iterator = generator();
        
        const handleNext = (result) => {
            if (result.done) {
                resolve(result.value);
                return;
            }
            const promise = result.value;
            promise
                .then((value) => {
                    handleNext(iterator.next(value));
                })
                .catch((error) => {
                    handleNext(iterator.throw(error));
                });
        };

        cancel = () => {
            reject("Cancelled");
        };

        try {
            handleNext(iterator.next());
        } catch (error) {
            reject(error);
        }
    });

    return [cancel, promise];
}
← Back to All Questions