Given an asynchronous function fn and a time t in milliseconds, return a new time limited version of the input function. fn takes arguments provided to the time limited function.
The time limited function should follow these rules:
fn completes within the time limit of t milliseconds, the time limited function should resolve with the result.fn exceeds the time limit, the time limited function should reject with the string "Time Limit Exceeded".
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}
Explanation:
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}
Explanation:
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}
Explanation:
The function resolved 5 + 10 = 15 at t=120ms. The time limit is never reached.
Example 4:
Input:
fn = async () => {
throw "Error";
}
inputs = []
t = 1000
Output: {"rejected":"Error","time":0}
Explanation:
The function immediately throws an error.
Constraints:
0 <= inputs.length <= 100 <= t <= 1000fn returns a promiseProblem Overview: You are given an asynchronous function fn and a time limit t. The goal is to return a new function that runs fn but rejects with "Time Limit Exceeded" if the promise does not resolve within t milliseconds.
Approach 1: Using Promise.race() (O(1) time, O(1) space)
The cleanest solution uses Promise.race(). Create two promises: one from the original function call fn(...args) and another timeout promise created with setTimeout that rejects after t milliseconds. Promise.race() resolves or rejects with whichever promise finishes first. If the function finishes before the timer, its result is returned. If the timer fires first, the wrapper rejects with the timeout error.
This approach relies on JavaScript's asynchronous event loop and promise scheduling. The key insight is that Promise.race() automatically handles the "first completed" behavior without manual state checks. It keeps the implementation small and readable, which is why it is the most common pattern used in real-world JavaScript systems when enforcing API or task deadlines.
Conceptually this pattern appears frequently in JavaScript async utilities and libraries that implement request timeouts or cancellation behavior around promises.
Approach 2: Manual Timeout Handling (O(1) time, O(1) space)
This approach manually constructs a new Promise and controls when it resolves or rejects. Inside the promise executor, start a setTimeout that triggers rejection after t milliseconds. Then execute fn(...args) and attach .then() and .catch() handlers. If the function finishes first, clear the timer using clearTimeout and resolve with the returned value.
This version gives you explicit control over the lifecycle of the timer and result propagation. The logic ensures only one outcome happens: either the timeout fires or the function completes. Manual handling is useful when implementing custom async utilities or debugging complex asynchronous programming flows where more control is needed beyond Promise.race().
Recommended for interviews: The Promise.race() solution is usually expected. It demonstrates that you understand promise composition and async control flow in JavaScript. Mentioning the manual timeout version shows deeper understanding of how promises and timers interact, but interviewers generally prefer the concise race-based implementation.
This approach leverages the Promise.race() function to race between the original asynchronous function and a timeout promise. If the function executes within the time limit, it resolves with the function's result. Otherwise, the timeout promise rejects with "Time Limit Exceeded."
This code wraps the original function within an asynchronous function that introduces a race condition between the function and a timeout duration using Promise.race(). If fn completes within t milliseconds, its resolved value is returned; otherwise, it gets rejected.
JavaScript
Time Complexity: O(1) — The best and worst case are consistent as it relies on how quickly the promise in fn resolves.
Space Complexity: O(1) — A constant amount of additional space is used.
This approach manually sets a timeout before invoking the asynchronous function and uses the result as a flag to determine if it has been reached. If the function attempt completes before the timeout, it clears the timeout; otherwise, it signals a reject using the timeout handler.
The code demonstrates a manual timeout mechanism coupled with Promise.race(). It introduces a timeout and clears it in finally to ensure the resource management is maintained cleanly. Upon completion of the main promise or timeout, it uses clearTimeout to avoid any further actions on the timer.
JavaScript
Time Complexity: O(1) — Performance does not vary significantly with time limit or function complexity.
Space Complexity: O(1) — Additional space is minimally affected by handling timeouts.
This approach utilizes Promise.race to handle the timeout. Promise.race allows us to race the original function's promise against a new promise that rejects after the specified duration t. If the original function resolves before the timeout, the new function resolves successfully. Otherwise, it rejects with a timeout error.
The function timeLimit wraps the original asynchronous function fn. It returns an asynchronous function that races fn(...args) with a timeout promise. The timeout promise calls setTimeout, which rejects after t milliseconds. If fn(...args) resolves before the timeout, the Promise.race resolves; otherwise, it rejects.
JavaScript
Time Complexity: O(1) — Relying on JavaScript's Promise system, where each promise has a negligible overhead.
Space Complexity: O(1) — Constant space used primarily for the setTimeout and the Promise itself.
This approach manually controls the timeout by creating a new promise that listens to both the resolution of fn and the timeout. By tracking which occurs first, we either resolve or reject appropriately. This approach sorts out through manual management of completion signals.
The function timeLimit creates and returns a new promise containing the logic to handle both the execution of fn and the timeout. It uses a flag isResolved to ensure that only the first completion (either the resolution of the fn function or the setTimeout) is applied. If the fn function resolves or rejects before the timeout, it handles those outcomes. Otherwise, it eventually triggers the timeout rejection.
JavaScript
Time Complexity: O(1) — The complexity is based on the constant time operations, with the Promise system operation being negligible.
Space Complexity: O(1) — Uses constant space for the timeout tracking and signal flags.
TypeScript
| Approach | Complexity |
|---|---|
| Approach 1: Using Promise.race() | Time Complexity: O(1) — The best and worst case are consistent as it relies on how quickly the promise in |
| Approach 2: Using Manual Timeout Handling | Time Complexity: O(1) — Performance does not vary significantly with time limit or function complexity. |
| Promise.race for Timeout | Time Complexity: O(1) — Relying on JavaScript's Promise system, where each promise has a negligible overhead. |
| Manual Promise Handling | Time Complexity: O(1) — The complexity is based on the constant time operations, with the Promise system operation being negligible. |
| Default Approach | — |
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Promise.race Timeout | O(1) | O(1) | Best general solution. Clean and concise way to enforce async time limits. |
| Manual Promise Timeout Handling | O(1) | O(1) | Useful when you need explicit control over timers and promise resolution. |
Promise Time Limit - Leetcode 2637 - JavaScript 30-Day Challenge • NeetCodeIO • 12,251 views views
Watch 9 more video solutions →Practice Promise Time Limit with our built-in code editor and test cases.
Practice on FleetCodePractice this problem
Open in Editor