Angular Custom Zone for Enhanced Event Handling
This challenge focuses on creating a custom zone in Angular to manage and track asynchronous operations within your application. Understanding and extending zones is crucial for advanced debugging, performance monitoring, and implementing sophisticated state management patterns. You will build a simplified version of zone functionality to observe and react to specific types of asynchronous events.
Problem Description
Your task is to create a custom Angular zone that intercepts and logs specific asynchronous operations triggered within the application. This custom zone should extend the default Angular zone (NgZone) and provide a mechanism to:
- Register for Events: Allow components or services to subscribe to notifications when certain types of asynchronous operations are initiated or completed.
- Intercept Operations: Capture and log specific asynchronous operations (e.g.,
setTimeout,setInterval, Promises). - Report Status: Provide a way to query the current status of tracked operations (e.g., active timers, pending promises).
Key Requirements:
- Create a custom Angular service that acts as the entry point for your custom zone.
- This service should wrap
NgZoneor directly interact with Zone.js to create and manage your custom zone. - Implement functionality to detect and log
setTimeoutandPromiseresolutions/rejections. - Provide methods for components to subscribe to notifications when a
setTimeoutstarts or aPromiseresolves/rejects. - Implement a method to report the number of active
setTimeoutcalls and pending promises.
Expected Behavior:
- When a
setTimeoutis scheduled within the custom zone, a notification should be emitted to all subscribed listeners. - When a
Promiseis created and subsequently resolved or rejected within the custom zone, a notification should be emitted. - Subscribers should be able to receive these notifications and react accordingly.
- The status reporting method should accurately reflect the current count of active timers and pending promises.
Edge Cases:
- Consider scenarios where multiple asynchronous operations are nested.
- Ensure proper cleanup and handling of timers that are cleared before they execute.
- Handle promises that resolve or reject synchronously.
Examples
Example 1: Basic Timer Tracking
// In a component:
constructor(private customZoneService: CustomZoneService) {
this.customZoneService.onTimerStart.subscribe(timerId => {
console.log(`Timer started with ID: ${timerId}`);
});
}
ngOnInit() {
setTimeout(() => {
console.log('Timer executed!');
}, 1000);
}
Expected Output in Console:
Timer started with ID: [some number]
Timer executed!
Explanation: The CustomZoneService intercepts the setTimeout call. It logs the timer's ID and emits an event. The component subscribes to this event and logs a message. The original setTimeout callback still executes as expected.
Example 2: Promise Tracking
// In a component:
constructor(private customZoneService: CustomZoneService) {
this.customZoneService.onPromiseComplete.subscribe(({ status, value }) => {
console.log(`Promise ${status}: ${JSON.stringify(value)}`);
});
}
async ngOnInit() {
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => resolve('Success!'), 500);
});
try {
const result = await myPromise;
console.log('Promise resolved in component.');
} catch (error) {
console.error('Promise rejected in component:', error);
}
}
Expected Output in Console:
Timer started with ID: [some number] // From the setTimeout inside the promise
Promise resolved: "Success!"
Promise resolved in component.
Explanation: The CustomZoneService intercepts the Promise creation and its resolution via setTimeout. It emits a onPromiseComplete event when the promise settles. The component logs the promise status and value.
Example 3: Status Reporting
// In a component:
constructor(private customZoneService: CustomZoneService) {}
ngOnInit() {
console.log('Initial timer count:', this.customZoneService.getActiveTimerCount());
const timerId = setTimeout(() => {}, 5000);
console.log('Timer count after scheduling:', this.customZoneService.getActiveTimerCount());
setTimeout(() => {
console.log('Timer count after execution:', this.customZoneService.getActiveTimerCount());
}, 6000);
}
Expected Output in Console:
Initial timer count: 0
Timer count after scheduling: 1
Timer count after execution: 0
Explanation: The getActiveTimerCount method returns the current number of scheduled but not yet executed setTimeout calls.
Constraints
- The custom zone implementation should be compatible with Angular's
NgZonelifecycle. - The solution should primarily use TypeScript.
- The number of concurrently active timers and pending promises should not exceed 1000 for performance testing purposes.
- The overhead introduced by the custom zone should be minimal, ensuring it doesn't significantly impact the application's performance for typical use cases.
Notes
- You will likely need to leverage the Zone.js library directly to create and patch specific asynchronous task APIs.
- Consider how to correctly associate events with the custom zone.
- Think about how to unpatch or revert changes made by Zone.js if necessary.
- You can use RxJS
SubjectorBehaviorSubjectfor emitting notifications to subscribers. - For timer tracking, you might need to patch
setTimeoutandclearTimeout. - For promise tracking, you might need to patch
Promise.resolve,Promise.reject, and thethen/catchmethods.