LeetCode Problem Workspace
Promise Time Limit
Implement a time-limited wrapper for any asynchronous function to enforce execution constraints and prevent overruns.
0
Topics
1
Code langs
0
Related
Practice Focus
Medium · Promise Time Limit core interview pattern
Answer-first summary
Implement a time-limited wrapper for any asynchronous function to enforce execution constraints and prevent overruns.
Ace coding interviews with Interview AiBoxInterview AiBox guidance for Promise Time Limit core interview pattern
This problem requires returning a version of a given asynchronous function that enforces a strict time limit. If the original function does not resolve within the specified milliseconds, the wrapper rejects with a Time Limit Exceeded message. Correct implementation ensures both proper resolution and timely rejection, testing understanding of promises, async handling, and timeout management.
Problem Statement
Given an asynchronous function fn and a time t in milliseconds, implement a function that returns a new version of fn that enforces the time limit. The new function should accept the same arguments as fn and return a promise.
The time-limited function should resolve with fn's result if it completes before t milliseconds, or reject with 'Time Limit Exceeded' if it exceeds the time limit. For example, if fn waits 100ms but the limit is 50ms, the promise must reject at 50ms.
Examples
Example 1
Input: fn = async (n) => { await new Promise(res => setTimeout(res, 100)); return n * n; } inputs = [5] t = 50
Output: {"rejected":"Time Limit Exceeded","time":50}
const limited = timeLimit(fn, t) const start = performance.now() let result; try { const res = await limited(...inputs) result = {"resolved": res, "time": Math.floor(performance.now() - start)}; } catch (err) { result = {"rejected": err, "time": Math.floor(performance.now() - start)}; } console.log(result) // Output
The provided function is set to resolve after 100ms. However, the time limit is set to 50ms. It rejects at t=50ms because the time limit was reached.
Example 2
Input: fn = async (n) => { await new Promise(res => setTimeout(res, 100)); return n * n; } inputs = [5] t = 150
Output: {"resolved":25,"time":100}
The function resolved 5 * 5 = 25 at t=100ms. The time limit is never reached.
Example 3
Input: fn = async (a, b) => { await new Promise(res => setTimeout(res, 120)); return a + b; } inputs = [5,10] t = 150
Output: {"resolved":15,"time":120}
The function resolved 5 + 10 = 15 at t=120ms. The time limit is never reached.
Constraints
- 0 <= inputs.length <= 10
- 0 <= t <= 1000
- fn returns a promise
Solution Approach
Use Promise.race to enforce the timeout
Wrap the original function call and a timeout promise using Promise.race. This ensures that whichever finishes first determines the outcome. Create a timeout promise that rejects after t milliseconds with 'Time Limit Exceeded'.
Return a wrapper function with correct argument forwarding
Define a higher-order function that takes fn and returns a new async function. Spread all received arguments when calling fn so that behavior remains consistent. This maintains compatibility with any input arity.
Handle both resolved and rejected cases carefully
The wrapper should correctly propagate fn's resolved value if it finishes in time, or the rejection reason if fn fails before the timeout. Avoid swallowing errors; always return a promise that accurately reflects the first completed outcome.
Complexity Analysis
| Metric | Value |
|---|---|
| Time | Depends on the final approach |
| Space | Depends on the final approach |
Time complexity depends on fn's execution and the set timeout, while space complexity is dominated by creating the wrapper and promises. Overhead is minimal and linear with argument count.
What Interviewers Usually Probe
- Looking for correct usage of Promise.race or equivalent time-limiting logic.
- Checking that arguments are passed correctly to the original function inside the wrapper.
- Observing handling of both resolved and rejected promises under time constraints.
Common Pitfalls or Variants
Common pitfalls
- Forgetting to reject the promise when the time limit is exceeded.
- Not forwarding arguments correctly to fn, causing unexpected behavior.
- Swallowing errors from fn instead of letting them propagate in the wrapper.
Follow-up variants
- Enforce different time limits dynamically per call instead of a fixed t.
- Apply the time-limiting pattern to multiple concurrent asynchronous functions.
- Return additional metadata like actual elapsed time alongside the resolved value or rejection.
FAQ
What is the main pattern in Promise Time Limit?
The core pattern is wrapping an async function with a time-limited promise using Promise.race to reject if execution exceeds the specified milliseconds.
How do I handle functions that resolve before the timeout?
Simply return the resolved value from the original function; Promise.race ensures the first completed promise determines the outcome.
Can the wrapper handle multiple arguments?
Yes, spread all arguments when calling the original function to maintain proper behavior for any input count.
What happens if fn itself rejects before the timeout?
The wrapper should propagate the rejection reason immediately; the timeout is only triggered if fn does not settle in time.
Is Promise Time Limit useful in real interview scenarios?
Yes, it tests knowledge of asynchronous control flow, timeout handling, and promise management under constraints.
Solution
Solution 1
#### TypeScript
type Fn = (...params: any[]) => Promise<any>;
function timeLimit(fn: Fn, t: number): Fn {
return async function (...args) {
return Promise.race([
fn(...args),
new Promise((_, reject) => setTimeout(() => reject('Time Limit Exceeded'), t)),
]);
};
}
/**
* const limited = timeLimit((t) => new Promise(res => setTimeout(res, t)), 100);
* limited(150).catch(console.log) // "Time Limit Exceeded" at t=100ms
*/