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.