Watch 10 video solutions for Interval Cancellation, a easy level problem. This walkthrough by Learn With Chirag has 2,465 views views. Want to try solving it yourself? Practice on FleetCode or read the detailed text solution.
Given a function fn, an array of arguments args, and an interval time t, return a cancel function cancelFn.
After a delay of cancelTimeMs, the returned cancel function cancelFn will be invoked.
setTimeout(cancelFn, cancelTimeMs)
The function fn should be called with args immediately and then called again every t milliseconds until cancelFn is called at cancelTimeMs ms.
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 functionargs is a valid JSON array1 <= args.length <= 1030 <= t <= 10010 <= cancelTimeMs <= 500Problem Overview: You need to implement a utility that repeatedly executes a function at fixed time intervals and returns a cancellation function. The function runs immediately, then continues running every t milliseconds until the returned cancel function stops the interval.
Approach 1: Using setInterval and clearInterval (O(1) time, O(1) space)
This approach relies directly on JavaScript’s built-in timer APIs. First, call fn(...args) immediately to satisfy the requirement that the function runs at time 0. Then create a repeating timer with setInterval that invokes the same function every t milliseconds. Store the interval ID returned by setInterval. The cancel function simply calls clearInterval(intervalId), which stops all future executions.
The key insight is that setInterval already handles repeated scheduling internally, so you only manage the initial call and the cancellation handle. This keeps the implementation minimal and avoids manual timer management. Setup cost is constant because you create a single interval and return a closure referencing its ID. This is the most idiomatic solution when working with JavaScript timer APIs.
Approach 2: Manual Loop with setTimeout (O(1) time, O(1) space)
This approach simulates interval behavior using repeated setTimeout calls. Start by executing fn(...args) immediately. Then define a helper function that schedules the next execution with setTimeout. Each time the timeout fires, it runs the function and schedules another timeout.
To support cancellation, track a boolean flag or the timeout ID. When the cancel function runs, update the flag or call clearTimeout to prevent the next scheduled execution. This technique is common in asynchronous programming when you need finer control over scheduling behavior compared to setInterval. It also avoids overlapping executions if a task takes longer than the interval.
The recursive scheduling pattern is slightly more verbose but flexible. Developers often prefer it when precise timing control or dynamic delays are required.
Recommended for interviews: The setInterval and clearInterval solution is the expected answer. It shows you understand how browser and Node.js timer functions work and how closures retain the interval ID for cancellation. The manual setTimeout loop demonstrates deeper understanding of scheduling mechanics and event-loop behavior, which can be useful if interviewers ask about alternative implementations.
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Using setInterval and clearInterval | O(1) setup | O(1) | Best general solution when implementing repeating timers in JavaScript |
| Manual Loop with setTimeout | O(1) setup | O(1) | Useful when you need finer control over scheduling or want to avoid overlapping executions |