Event Bus with Wildcard Subscriptions in JavaScript
Event buses provide a centralized mechanism for components to communicate without direct dependencies. This challenge asks you to implement a JavaScript event bus that supports both specific event subscriptions and wildcard subscriptions, allowing subscribers to listen for events matching a pattern. This is useful for decoupling components and creating flexible, reactive systems.
Problem Description
You are tasked with creating a JavaScript class called EventBus that manages event subscriptions and dispatches events. The EventBus should provide the following functionalities:
subscribe(event, callback): Registers acallbackfunction to be executed when theeventis dispatched. Theeventcan be a string representing a specific event name or a string with a wildcard character*. Wildcards match any event name that starts with the specified prefix. For example,'user.*'would match'user.created','user.updated', and'user.deleted'.unsubscribe(event, callback): Removes the specifiedcallbackfunction from the list of subscribers for the givenevent. If theeventis a wildcard, it removes all callbacks subscribed to that wildcard.dispatch(event, data): Triggers all registered callbacks for the givenevent. Thedataargument is passed to each callback function. If theeventis a wildcard, it iterates through all events matching the wildcard pattern and executes the corresponding callbacks.
Key Requirements:
- The
EventBusshould handle multiple subscribers for the same event. - The
unsubscribemethod should correctly remove the specified callback. - Wildcard subscriptions should correctly match events based on the prefix.
- The
dispatchmethod should pass the provideddatato the callbacks. - The implementation should be efficient and avoid unnecessary iterations.
Expected Behavior:
- Subscribing to an event should add the callback to the appropriate subscriber list.
- Unsubscribing should remove the callback.
- Dispatching an event should execute all matching callbacks with the provided data.
- Dispatching an event with no subscribers should not throw an error.
- Unsubscribing a callback that wasn't subscribed should not throw an error.
Edge Cases to Consider:
- Empty event names.
- Callbacks that are not functions.
- Wildcards at the end of the event name (e.g.,
*). - Multiple wildcards in the event name (e.g.,
user.*.*). (For simplicity, assume only one wildcard is used.) - Unsubscribing a callback that doesn't exist.
- Dispatching an event with no data.
Examples
Example 1:
Input:
eventBus.subscribe('user.created', (data) => console.log('User created:', data));
eventBus.dispatch('user.created', { id: 1, name: 'Alice' });
Output:
User created: { id: 1, name: 'Alice' }
Explanation: The callback subscribed to 'user.created' is executed with the provided data.
Example 2:
Input:
eventBus.subscribe('user.*', (data) => console.log('User event:', data));
eventBus.dispatch('user.updated', { id: 1, name: 'Bob' });
eventBus.unsubscribe('user.*', (data) => console.log('User event:', data));
eventBus.dispatch('user.deleted', { id: 2 });
Output:
User event: { id: 1, name: 'Bob' }
Explanation: The wildcard subscription 'user.*' matches 'user.updated', executing the callback. The callback is then unsubscribed, so 'user.deleted' does not trigger it.
Example 3:
Input:
eventBus.subscribe('system.error', (data) => console.log('System error:', data));
eventBus.dispatch('other.event', { message: 'Some message' });
eventBus.dispatch('system.error', { code: 500, message: 'Internal Server Error' });
Output:
System error: { code: 500, message: 'Internal Server Error' }
Explanation: Only the callback subscribed to 'system.error' is executed, as 'other.event' does not match any subscription.
Constraints
- The
eventstring can be up to 255 characters long. - The
callbackfunction must be a function. - The
datapassed to the callback can be any JavaScript value. - The implementation should have a time complexity of O(n) for
dispatchin the worst case, where n is the number of matching subscribers.subscribeandunsubscribeshould ideally be O(1) or O(n) where n is the number of subscribers for a specific event/wildcard.
Notes
- Consider using a data structure (e.g., a Map or object) to store subscriptions efficiently.
- The wildcard matching should be based on string prefix comparison.
- Think about how to handle errors gracefully, such as when a callback is not a function.
- Focus on creating a clean, readable, and well-documented implementation.
- You do not need to worry about thread safety or asynchronous operations.