Implementing a Time-To-Live (TTL) Cache in JavaScript
Caching is a crucial technique for optimizing performance by storing frequently accessed data and retrieving it quickly. This challenge asks you to implement a simple in-memory cache in JavaScript that supports a Time-To-Live (TTL) for cached items. This is useful for scenarios where data freshness is important and you want to automatically expire old data.
Problem Description
You need to create a Cache class in JavaScript. This class should allow you to store key-value pairs, with each key-value pair having an associated TTL (in milliseconds). The cache should automatically remove entries that have exceeded their TTL. The class should provide the following methods:
set(key, value, ttl): Stores a key-value pair in the cache.keyis a string,valuecan be any JavaScript data type, andttlis the time-to-live in milliseconds.get(key): Retrieves the value associated with a given key. If the key exists and the TTL hasn't expired, return the value. If the key doesn't exist or the TTL has expired, returnundefined.delete(key): Removes a key-value pair from the cache.clear(): Removes all entries from the cache.
The cache should internally manage the expiration of entries using setTimeout.
Examples
Example 1:
Input:
cache = new Cache();
cache.set("name", "John Doe", 2000);
console.log(cache.get("name"));
setTimeout(() => { console.log(cache.get("name")); }, 3000);
Output:
John Doe
undefined
Explanation: The name key is set with a TTL of 2 seconds. The first get call retrieves "John Doe" immediately. After 3 seconds (longer than the TTL), the second get call returns undefined because the entry has expired.
Example 2:
Input:
cache = new Cache();
cache.set("data", { value: 10 }, 5000);
cache.delete("data");
console.log(cache.get("data"));
Output:
undefined
Explanation: The data key is set with a TTL of 5 seconds. The delete method removes the entry before it expires, so get returns undefined.
Example 3: (Edge Case - Concurrent Access)
Input:
cache = new Cache();
cache.set("item", "value", 1000);
setTimeout(() => { console.log(cache.get("item")); }, 500); // Access before TTL expires
setTimeout(() => { console.log(cache.get("item")); }, 1500); // Access after TTL expires
Output:
value
undefined
Explanation: Demonstrates that the cache correctly handles access before and after the TTL expires.
Constraints
ttlvalues will always be non-negative integers.- Keys will always be strings.
- The cache should be thread-safe (although JavaScript is single-threaded, consider potential issues if used in a multi-threaded environment - focus on avoiding race conditions within the cache's internal logic).
- The
setmethod should not block the main thread for extended periods. UsesetTimeoutappropriately. - The cache should not leak memory. Expired timers should be properly cleaned up.
Notes
- Consider using a
Mapfor efficient key-value storage. - The
setTimeoutfunction will be crucial for managing TTLs. Make sure to store the timeout ID so you can clear it if the entry is deleted before it expires. - Think about how to handle the case where an entry is deleted before its TTL expires. You should cancel the associated timeout.
- Focus on clarity and maintainability of your code. Good variable names and comments are appreciated.
- While a production-ready cache would likely involve more sophisticated eviction strategies and concurrency controls, this challenge focuses on the core TTL functionality.