Cancellable Function Solution with Full Testing Breakdown
Intuition\nWe need to delay the execution of a function named fn which will be passed as an argument to our cancallable() function. The trick is we need to canc
# Intuition\nWe need to delay the execution of a function named `fn` which will be passed as an argument to our `cancallable()` function. The trick is we need to cancel the execution of `fn()` if the cancel function `cancelFn` is invoked before `fn()` is executed.\n\n# Approach\nIn order to solve this problem, we need to:\n\n1. Call `setTimeout()` function to delay the execution of `fn` by `t` amount of time. But calling this function is not enough alone, we also store the timeout ID which will be returned from `setTimeout()`. We need this `timeoutID` because in the next step we are going to use it in another function.\n\n2. Now define a new function named `cancelFn` as inner function. This function doesn\'t return any value, but it will execute `clearTimeout()` function when it\'s called. In other words, our outer function `cancellable` will return `cancelFn`, but our inner function `cancelFn` won\'t return anything. It will just call `clearTimeout()`.The javaScript function `clearTimeout()` simply takes a parameter as timeoutID, because it should know which timeout it going to clear. That is why we stored `timeoutID` of `setTimeout()` in step 1.\n\n3. Last step is returning `cancelFn`. That\'s it.\n\n# Description\n```\nconst start = performance.now();\n```\n\n`performance.now()` captures current time. This is going to used to measure the execution time.\n\n```\nconst log = (...argsArr) => {\n    const diff = Math.floor(performance.now() - start);\n    result.push({"time": diff, "returned": fn(...argsArr)});\n}\n```\n\nHere `diff` will be the time difference between the start time of code and call time of `log(...argsArr)` function. Then it pushed the variable `diff` and the result of function which is `fn(...argsArr)` to the array named `result`. Later this `log(...argsArr)` function will be passed to the `cancellable()` function as an argument.\n\n```\nconst cancel = cancellable(log, args, t);\n```\n\nThe return value of `cancellable()` which is `cancelFn()` is assigned to the `cancel`. `log`,`args`, and `t` are passed as argument to the `cancellable(log, args, t)`.\nIf you wonder why it has passed `log()` instead of `fn()` to the `cancellable()`, the first parameter of `cancellable()` was `fn` by default not `log`, then the answer is: `fn()` function is already called and pushed to the `result` array inside `log()` function. Moreover the `log()` function consist of time `diff` which is going to used in testing the code by checking the time. So instead of passing the time `diff` and the `fn()` function iteself, they merged these two inside of one function named `log()`.\n\n```\nconst maxT = Math.max(t, cancelTimeMs);\n```\n\n`Math.max()` decides which of it\'s arguments is bigger. It assigns bigger integer to the `maxT`. This variable will be used to log the result after execution/cancellation of `fn()`.\n\n```\nsetTimeout(cancel, cancelTimeMs);\n```\n\nThis line schedules the execution of `cancel()`, which is `cancelFn`, to occur after `cancelTimeMs` milliseconds.\nSo if the argument `fn()` in `cancellable()` doesn\'t execute before `cancelTimeMs`, the Schedule will be cancelled.\nIn other words, if we want to execute `fn()`, then `t` must be lower or equal to the `cancelTimeMs`. \n\n```\n setTimeout(() => {\n     console.log(result);\n }, maxT + 15)\n```\n\nThis part just prints the result to the console after `maxT` + 15 miliseconds. Since we want to test it, we should see the output in the console. Thus result should be executed after `t` or `cancelTimeMs` whichever is higher. + 15 is just a small additional delay to ensure that the previous `setTimeout()` have completed before the result is logged.\n\n\n# Complexity\n- Time complexity:\nSince `setTimeout()` and `clearTimeout()` functions ocur in constant time regardless of the input size, the time complexity will be: \n\n    $$O(1)$$\n\n\n- Space complexity:\nIn this solution we only stored one variable(`timeoutID`),and a function reference(`cancelFn()`). Thus the space complexity will be: \n\n    $$O(1)$$\n\n# Code\n```javascript []\n/**\n * @param {Function} fn\n * @param {Array} args\n * @param {number} t\n * @return {Function}\n */\nvar cancellable = function(fn, args, t) {\n    let timeoutId;\n\n    const cancelFn = () => {\n        clearTimeout(timeoutId);\n    };\n\n    timeoutId = setTimeout(() => {\n        fn(...args);\n    }, t);\n\n    return cancelFn;\n};\n\n/**\n *  const result = [];\n *\n *  const fn = (x) => x * 5;\n *  const args = [2], t = 20, cancelTimeMs = 50;\n *\n *  const start = performance.now();\n *\n *  const log = (...argsArr) => {\n *      const diff = Math.floor(performance.now() - start);\n *      result.push({"time": diff, "returned": fn(...argsArr)});\n *  }\n *       \n *  const cancel = cancellable(log, args, t);\n *\n *  const maxT = Math.max(t, cancelTimeMs);\n *           \n *  setTimeout(cancel, cancelTimeMs);\n *\n *  setTimeout(() => {\n *      console.log(result); // [{"time":20,"returned":10}]\n *  }, maxT + 15)\n */\n```
['JavaScript']