Interval Cancellation

Updated on 17 June, 2025
Interval Cancellation header image

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

  • fn is a function
  • args is a valid JSON array
  • 1 <= args.length <= 10
  • 30 <= t <= 100
  • 10 <= 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:

  1. Initial and Periodic Invocation:
    • We immediately invoke the function fn with the provided arguments args.
    • We then use JavaScript's setInterval to continue calling fn every t milliseconds.
  2. Cancellation:
    • A cancel function, cancelFn, when executed, should use clearInterval to stop any further executions scheduled by setInterval.
    • This cancelFn is scheduled to run after cancelTimeMs milliseconds using setTimeout. Thus, ensuring no further calls to fn occur past this point.

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
js
/**
 * @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 repeatableWithCancel with 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 of functionToRun.
  • Inside repeatableWithCancel, initialize a variable currentTimer to null, which will later store the reference to the timeout.

  • Execute the functionToRun immediately with the provided parameters using the spread syntax (...parameters).

  • Define initiateTimer, a function that sets a timeout which executes functionToRun using the provided parameters after a delay of repeatTime, 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 the repeatableWithCancel function.

  • Define the function stopTimer which, when called, checks if currentTimer is not null and, if so, uses clearTimeout to stop the timeout, effectively cancelling the repetitive execution.

  • Return stopTimer from repeatableWithCancel. 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.

Comments

No comments yet.