Back to blog
Dec 16, 2025
4 min read

Timeout Cancellation

Implement a cancellable timeout function that executes a given function after a delay, with the ability to cancel the execution.

Difficulty: Easy | Acceptance: 89.50% | Paid: No Topics: N/A

Given a function fn, an array of arguments args, and a timeout t in milliseconds, return a cancel function cancelFn.

After a delay of t, fn should be called with args passed to it.

The cancelTimeFn function should clear the scheduled timeout.

The following is the example of how the cancelTimeFn will be used:

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 cancelT = setTimeout(() => {
    cancel()
}, cancelTimeMs)

setTimeout(() => {
    clearTimeout(cancelT)
}, cancelTimeMs + t + 100)

Examples

Example 1

Input:

fn = (x) => x * 5, args = [2], t = 20

Output:

[{"time":20,"returned":10}]

Explanation:

const cancelTimeMs = 50;
const cancel = cancellable(fn, args, t);
setTimeout(cancel, cancelTimeMs);

The cancellation was scheduled to occur after 50ms, but the fn was executed at 20ms, so the cancellation had no effect.

Example 2

Input:

fn = (x) => x ** 2, args = [2], t = 100

Output:

[]

Explanation:

const cancelTimeMs = 50;
const cancel = cancellable(fn, args, t);
setTimeout(cancel, cancelTimeMs);

The cancellation was scheduled to occur after 50ms, and fn was never executed.

Example 3

Input:

fn = (x1, x2) => x1 * x2, args = [2,4], t = 30

Output:

[{"time":30,"returned":8}]

Explanation:

const cancelTimeMs = 100;
const cancel = cancellable(fn, args, t);
setTimeout(cancel, cancelTimeMs);

The cancellation was scheduled to occur after 100ms, and fn was executed at 30ms, so the cancellation had no effect.

Constraints

fn is a function
args is a valid JSON array
1 <= args.length <= 10
2 <= t <= 1000
1 <= cancelTimeMs <= 1000

setTimeout and clearTimeout

Intuition Use JavaScript’s built-in setTimeout to schedule the function execution and clearTimeout to cancel it before it runs.

Steps

  • Create a timeout using setTimeout that calls fn with spread arguments after t milliseconds
  • Store the timeout ID returned by setTimeout
  • Return a cancel function that uses clearTimeout with the stored ID to cancel the scheduled execution
python
import threading

def cancellable(fn, args, t):
    timer = threading.Timer(t / 1000, lambda: fn(*args))
    timer.start()
    
    def cancel_fn():
        timer.cancel()
    
    return cancel_fn

Complexity

  • Time: O(1) for setup and cancellation
  • Space: O(1) - only stores the timeout ID
  • Notes: Most efficient approach using native browser APIs

Promise with Cancellation Flag

Intuition Wrap the timeout logic in a Promise and use a boolean flag to track whether cancellation has occurred before execution.

Steps

  • Create a cancelled flag initialized to false
  • Create a Promise that resolves after t milliseconds
  • Inside the Promise callback, check if not cancelled before executing fn
  • Return a cancel function that sets the cancelled flag to true
python
import threading

def cancellable(fn, args, t):
    cancelled = threading.Event()
    
    def execute():
        cancelled.wait(t / 1000)
        if not cancelled.is_set():
            fn(*args)
    
    thread = threading.Thread(target=execute)
    thread.start()
    
    def cancel_fn():
        cancelled.set()
    
    return cancel_fn

Complexity

  • Time: O(1) for setup and cancellation
  • Space: O(1) - only stores the cancellation flag
  • Notes: Less efficient than clearTimeout as the timeout still completes internally

Async/Await with Cancellation

Intuition Use async/await syntax with a cancellation flag to handle the delayed execution in a more readable, modern JavaScript style.

Steps

  • Create a shouldCancel flag initialized to false
  • Define an async function that awaits a Promise-based delay of t milliseconds
  • After the delay, check if not cancelled before executing fn
  • Start the async execution immediately
  • Return a cancel function that sets the shouldCancel flag to true
python
import asyncio

def cancellable(fn, args, t):
    cancelled = False
    
    async def execute():
        await asyncio.sleep(t / 1000)
        nonlocal cancelled
        if not cancelled:
            fn(*args)
    
    # Start the coroutine as a task
    loop = asyncio.get_event_loop()
    loop.create_task(execute())
    
    def cancel_fn():
        nonlocal cancelled
        cancelled = True
    
    return cancel_fn

Complexity

  • Time: O(1) for setup and cancellation
  • Space: O(1) - only stores the cancellation flag
  • Notes: More readable syntax but functionally similar to Promise approach