Hone logo
Hone
Problems

Reactive Dependency Tracker in JavaScript

This challenge asks you to build a simple reactive dependency tracker in JavaScript. Reactive systems automatically update dependent components when their dependencies change, a core concept in frameworks like React and Vue.js. Building a basic dependency tracker will help you understand the underlying principles of reactivity.

Problem Description

You need to create a DependencyTracker class that allows you to register dependencies and automatically notify subscribers when those dependencies change. The tracker should maintain a mapping of dependencies to their subscribers. When a dependency's value is updated, all registered subscribers for that dependency should be notified.

Key Requirements:

  • addDependency(key, initialValue): Adds a new dependency to the tracker. key is a string representing the dependency's name, and initialValue is the initial value of the dependency.
  • subscribe(key, subscriber): Registers a subscriber function to be notified when the value of the dependency key changes. The subscriber function should accept the new value of the dependency as its argument.
  • unsubscribe(key, subscriber): Removes a subscriber from the list of subscribers for the dependency key.
  • update(key, newValue): Updates the value of the dependency key to newValue. This should trigger all subscribers for that dependency.
  • get(key): Returns the current value of the dependency key. If the key doesn't exist, return undefined.

Expected Behavior:

  • Subscribers should be notified only when the dependency's value actually changes.
  • Multiple subscribers can be registered for the same dependency.
  • Unsubscribing a subscriber should prevent it from being notified in the future.
  • The tracker should handle cases where a dependency is updated before any subscribers are registered.
  • The tracker should handle cases where a dependency is accessed before it is initialized.

Edge Cases to Consider:

  • What happens if addDependency is called with the same key multiple times? (Should overwrite the previous value and subscribers).
  • What happens if subscribe is called with a key that doesn't exist? (Should be a no-op).
  • What happens if unsubscribe is called with a key that doesn't exist, or with a subscriber that wasn't registered? (Should be a no-op).
  • What happens if update is called with a key that doesn't exist? (Should be a no-op).
  • What happens if get is called with a key that doesn't exist? (Should return undefined).

Examples

Example 1:

Input:
tracker = new DependencyTracker();
tracker.addDependency("name", "Alice");
let subscriber1 = (newValue) => console.log("Subscriber 1: " + newValue);
tracker.subscribe("name", subscriber1);
tracker.update("name", "Bob");

Output:
Subscriber 1: Bob

Explanation:
The dependency "name" is added with the initial value "Alice".  subscriber1 is registered to listen for changes to "name".  When "name" is updated to "Bob", subscriber1 is called with the new value.

Example 2:

Input:
tracker = new DependencyTracker();
tracker.addDependency("count", 0);
let subscriber1 = (newValue) => console.log("Subscriber 1: " + newValue);
let subscriber2 = (newValue) => console.log("Subscriber 2: " + newValue);
tracker.subscribe("count", subscriber1);
tracker.subscribe("count", subscriber2);
tracker.unsubscribe("count", subscriber1);
tracker.update("count", 5);

Output:
Subscriber 2: 5

Explanation:
"count" is initialized to 0. Both subscriber1 and subscriber2 are registered. subscriber1 is then unsubscribed. When "count" is updated to 5, only subscriber2 is called.

Example 3: (Edge Case)

Input:
tracker = new DependencyTracker();
let subscriber1 = (newValue) => console.log("Subscriber 1: " + newValue);
tracker.subscribe("age", subscriber1); // Subscribe before adding dependency
tracker.addDependency("age", 30);
tracker.update("age", 31);

Output:
Subscriber 1: 31

Explanation:
The subscriber is registered before the dependency is added. The dependency "age" is then added with the value 30, and when it's updated to 31, subscriber1 is correctly notified.

Constraints

  • The key for a dependency must be a string.
  • The subscriber must be a function that accepts a single argument (the new value).
  • The tracker should be able to handle at least 100 dependencies and 1000 subscribers per dependency without significant performance degradation. (This is a guideline, not a strict limit).
  • The initial value of a dependency can be of any JavaScript data type.

Notes

  • Consider using JavaScript objects or Maps to store dependencies and subscribers.
  • Think about how to efficiently manage the list of subscribers for each dependency.
  • Focus on clarity and maintainability of your code. Good variable names and comments are encouraged.
  • This is a simplified version of a reactive system. Real-world reactive systems often involve more complex features like dependency cycles and optimized update strategies. Don't worry about those for this challenge.
  • Error handling is not required for this challenge. Assume valid input.
Loading editor...
javascript