
Problem Statement
In this task, we are given a function fn along with an array args containing its arguments, and a specific time interval t. The objective is to construct and return a cancel function, cancelFn, that when invoked, stops the periodic execution of fn. Initially, fn is executed with the arguments from args and then repeatedly executed after every t milliseconds. This periodic invocation continues until cancelFn is triggered at a specified delay cancelTimeMs, which halts further executions of fn.
The challenge encompasses setting up the initial and periodic invocation of fn using JavaScript's setTimeout or similar mechanism, and managing its cancellation after cancelTimeMs has elapsed using the cancelFn function.
Examples
Example 1
Input:
fn = (x) => x * 2, args = [4], t = 35
Output:
[
{"time": 0, "returned": 8},
{"time": 35, "returned": 8},
{"time": 70, "returned": 8},
{"time": 105, "returned": 8},
{"time": 140, "returned": 8},
{"time": 175, "returned": 8}
]Explanation:
const cancelTimeMs = 190; const cancelFn = cancellable((x) => x * 2, [4], 35); setTimeout(cancelFn, cancelTimeMs); Every 35ms, fn(4) is called. Until t=190ms, then it is cancelled. 1st fn call is at 0ms. fn(4) returns 8. 2nd fn call is at 35ms. fn(4) returns 8. 3rd fn call is at 70ms. fn(4) returns 8. 4th fn call is at 105ms. fn(4) returns 8. 5th fn call is at 140ms. fn(4) returns 8. 6th fn call is at 175ms. fn(4) returns 8. Cancelled at 190ms
Example 2
Input:
fn = (x1, x2) => (x1 * x2), args = [2, 5], t = 30
Output:
[
{"time": 0, "returned": 10},
{"time": 30, "returned": 10},
{"time": 60, "returned": 10},
{"time": 90, "returned": 10},
{"time": 120, "returned": 10},
{"time": 150, "returned": 10}
]Explanation:
const cancelTimeMs = 165; const cancelFn = cancellable((x1, x2) => (x1 * x2), [2, 5], 30) setTimeout(cancelFn, cancelTimeMs) Every 30ms, fn(2, 5) is called. Until t=165ms, then it is cancelled. 1st fn call is at 0ms 2nd fn call is at 30ms 3rd fn call is at 60ms 4th fn call is at 90ms 5th fn call is at 120ms 6th fn call is at 150ms Cancelled at 165ms
Example 3
Input:
fn = (x1, x2, x3) => (x1 + x2 + x3), args = [5, 1, 3], t = 50
Output:
[
{"time": 0, "returned": 9},
{"time": 50, "returned": 9},
{"time": 100, "returned": 9},
{"time": 150, "returned": 9}
]Explanation:
const cancelTimeMs = 180; const cancelFn = cancellable((x1, x2, x3) => (x1 + x2 + x3), [5, 1, 3], 50) setTimeout(cancelFn, cancelTimeMs) Every 50ms, fn(5, 1, 3) is called. Until t=180ms, then it is cancelled. 1st fn call is at 0ms 2nd fn call is at 50ms 3rd fn call is at 100ms 4th fn call is at 150ms Cancelled at 180ms
Constraints
fnis a functionargsis a valid JSON array1 <= args.length <= 1030 <= t <= 10010 <= cancelTimeMs <= 500
Approach and Intuition
The objective is to implement a functionality where a function fn can be scheduled to run at an interval of t milliseconds and can be programmatically stopped at a specific time cancelTimeMs. This can be visualized through two primary operations:
- Initial and Periodic Invocation:
- We immediately invoke the function
fnwith the provided argumentsargs. - We then use JavaScript's
setIntervalto continue callingfneverytmilliseconds.
- We immediately invoke the function
- Cancellation:
- A cancel function,
cancelFn, when executed, should useclearIntervalto stop any further executions scheduled bysetInterval. - This
cancelFnis scheduled to run aftercancelTimeMsmilliseconds usingsetTimeout. Thus, ensuring no further calls tofnoccur past this point.
- A cancel function,
The examples provided simulate this behavior:
- Example 1: A multiplication function is invoked repeatedly every 35 milliseconds and stops at 190 milliseconds.
- Example 2: A product function for two numbers runs every 30 milliseconds and halts at 165 milliseconds.
- Example 3: A summation function runs every 50 milliseconds and is canceled at 180 milliseconds.
In each case, the output reflects the results of fn at each invocation until it is stopped by cancelFn. Each of these settings adheres to the specified constraints regarding the number of arguments, the interval t, and the maximum duration before cancellation cancelTimeMs.
Solutions
- JavaScript
/**
* @param {Function} functionToRun
* @param {Array} parameters
* @param {number} repeatTime
* @return {Function}
*/
var repeatableWithCancel = function(functionToRun, parameters, repeatTime) {
let currentTimer = null;
functionToRun(...parameters);
const initiateTimer = () => {
currentTimer = setTimeout(() => {
functionToRun(...parameters);
initiateTimer();
}, repeatTime);
};
initiateTimer();
const stopTimer = () => {
if (currentTimer !== null) {
clearTimeout(currentTimer);
}
};
return stopTimer;
};
The JavaScript solution provided defines a function called repeatableWithCancel that accepts three parameters: functionToRun, parameters, and repeatTime. This function is designed to repeatedly execute a specified function at defined intervals, which can be programmatically cancelled when needed.
Begin by defining the function
repeatableWithCancelwith three parameters:functionToRun: The function you wish to execute repeatedly.parameters: An array of arguments to pass to the function being invoked.repeatTime: The time interval (in milliseconds) between successive invocations offunctionToRun.
Inside
repeatableWithCancel, initialize a variablecurrentTimertonull, which will later store the reference to the timeout.Execute the
functionToRunimmediately with the providedparametersusing the spread syntax (...parameters).Define
initiateTimer, a function that sets a timeout which executesfunctionToRunusing the providedparametersafter a delay ofrepeatTime, and recursively calls itself. This creates an indefinite loop of function execution at the specified interval.Initialize the timer with a call to
initiateTimer()directly within therepeatableWithCancelfunction.Define the function
stopTimerwhich, when called, checks ifcurrentTimeris notnulland, if so, usesclearTimeoutto stop the timeout, effectively cancelling the repetitive execution.Return
stopTimerfromrepeatableWithCancel. This returned function can be called to stop the timer at any point, providing control over when to stop the repetitive actions.
This implementation allows the user to create a setup where function executions can be repeated at intervals with the flexibility to stop the repetition whenever required. Keep in mind to start the timer immediately and allow for its cancellation through the function returned by repeatableWithCancel.