In RxJS several observable have cleanup function ran at unsubscription, such as timer()
. I’m trying to understand what’s the best approach to implement that in pure signal. Some of my attempts on stackblitz.
The below code shows how one could implement a timer from the ground up in RxJS:
function getTimerRxjs(frequency: number): Observable<number> {
// Below code is equivalent to timer(frequency)
return new Observable((observer) => {
let value = 0;
let lastTimeout;
const loop = () => {
console.log('getTimerRxjs loop is running');
observer.next(value);
value += 1;
lastTimeout = setTimeout(loop, frequency);
};
lastTimeout = setTimeout(loop, frequency);
return () => {
if (lastTimeout) clearTimeout(lastTimeout);
};
});
}
Option A: In an attempt to reproduce a similar behavior, you could pass DestroyRef to the function generating the timer as follow:
function getTimerWithRef(frequency: number, destroyRef: DestroyRef): Signal<number> { const timer = signal(-1); let lastTimeout; const loop = () => { console.log('getTimerWithRef loop is running'); timer.update((value) => value + 1); lastTimeout = setTimeout(loop, frequency); }; lastTimeout = setTimeout(loop, frequency); destroyRef.onDestroy(() => { if (lastTimeout) clearTimeout(lastTimeout); }); return timer; }
Option B: You could inject destroyRef at runtime in the function as follow:
function getTimerAutoCleanup(frequency: number): Signal<number> { const timer = signal(-1); let lastTimeout; const loop = () => { console.log('getTimerAutoCleanup loop is running'); timer.update((value) => value + 1); lastTimeout = setTimeout(loop, frequency); }; lastTimeout = setTimeout(loop, frequency); inject(DestroyRef).onDestroy(() => { if (lastTimeout) clearTimeout(lastTimeout); }); return timer; }
While Option B seems elegant, I fear the inject()
call may not resolve to the correct context.
- If create this signal from an
@Injectable()
, would theinject(DestroyRef)
resolve to the component or to the service? - Are there other risks of using Option B where some injection error may only surface at runtime?
I need help to find which option would be more idiomatic in this context.