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.