ProphesierC - Timeout Cancellation using Closures
IntuitionThe goal is to create a function that schedules another function to run after a specified time but allows for cancellation before it runs. By using Jav
# Intuition
The goal is to create a function that schedules another function to run after a specified time but allows for cancellation before it runs. By using JavaScript's `setTimeout`, we can schedule the function and capture its ID to later cancel the execution if needed.

### Closure Formation:

- The inner function (returned by cancellable) forms a closure over the timeoutId variable declared in the outer function (cancellable). This means that even after cancellable has finished executing, the returned function can still access and modify timeoutId.
### Scheduling with setTimeout:

- Inside the cancellable function, setTimeout(() => fn(...args), t) schedules the execution of fn with its arguments args after t milliseconds. The setTimeout call returns a timeout ID which is stored in timeoutId.

### Canceling the Timeout:

- The returned function uses clearTimeout(timeoutId) to cancel the pending setTimeout operation whenever it is invoked. This prevents fn from executing if the cancellation occurs before the specified time t.

# Approach

1. **Schedule Function Execution**: Use `setTimeout` to schedule the execution of the provided function `fn` with its arguments after `t` milliseconds.
2. **Capture Timeout ID**: Store the timeout ID returned by `setTimeout` so it can be used later for cancellation.
3. **Return Cancel Function**: The returned function uses `clearTimeout` with the stored timeout ID to cancel the scheduled execution whenever it is called.

This approach leverages closures to keep track of the timeout ID, enabling the canceling mechanism.

# Complexity

- Time complexity: O(1)
Both setTimeout and clearTimeout operations are executed in constant time as they involve simple internal bookkeeping without proportional resource usage relative to input size.

- Space Complexity: O(1)
The space complexity is constant because only a single timeout ID and the closure over it are stored, regardless of the input size.

# Code
```javascript []
/**
 * @param {Function} fn
 * @param {Array} args
 * @param {number} t
 * @return {Function}
 */
const cancellable = function(fn, args, t) {
    const timeoutId = setTimeout(() => {
        fn(...args);  
    }, t);

    return function() {
        clearTimeout(timeoutId);
    };
};

/**
 *  const result = [];
 *
 *  const fn = (x) => x * 5;
 *  const args = [2], t = 20, cancelTimeMs = 50;
 *
 *  const start = performance.now();
 *
 *  const log = (...argsArr) => {
 *      const diff = Math.floor(performance.now() - start);
 *      result.push({"time": diff, "returned": fn(...argsArr)});
 *  }
 *       
 *  const cancel = cancellable(log, args, t);
 *
 *  const maxT = Math.max(t, cancelTimeMs);
 *           
 *  setTimeout(cancel, cancelTimeMs);
 *
 *  setTimeout(() => {
 *      console.log(result); // [{"time":20,"returned":10}]
 *  }, maxT + 15)
 */
```
['JavaScript']