I’m having a tough time thinking of any other topic where there is a greater chasm between “how simple it sounds” and “how bletcherously complex it is”. Innumerable libraries and arguable the very concept of push notifications itself have been written to try to facilitate it.
For a variety of reasons, including simplicity and efficiency, push notifications are the best way to do it, and second place isn’t close.
However, you say that’s not possible. I even think setting up a secondary proxy server that you can control, and getting it to deliver push notifications would, in the end, be preferable to any polling / scraping solution that you probably have percolating in your mind at the moment.
Probably best to stop reading at this point.
Still here, huh?
Don’t say I didn’t warn you.
Fine.
I have an idiom that I call Channel
that I borrowed loosely from the similarly-named concept in Golang. It’s designed for bidirectional communication, but it sounds like you only want one-way, so I’ll strip out the transmit parts.
interface Channel<T> {
readonly feed$: Observable<T>;
readonly onair: T | null;
refresh(): Observable<any>;
// a channel is burned once you call teardown on it
teardown(): void;
}
The pairing of feed$
and onair
can easily be implemented by a single BehaviorSubject
. For example, here is an ImmutableChannel
:
class ImmutableChannel<T> implements Channel<T> {
readonly feed$: BehaviorSubject<T>;
constructor(val: T) {
this.feed$ = new BehaviorSubject<T>(val);
}
get onair(): T {
return this.feed$.value;
}
refresh(): Observable<any> {
// you will initially be tempted to write this as of()
// then you will discover that of() completes without emitting,
// which breaks a whole host of idioms that expect refresh() to emit *something*
return of(void 0);
}
}
You should be able to adapt this to deliver what looks to your client code like a stream of data that can be refreshed manually as desired (something you will very likely decide you want in addition to periodic polling). Periodic polling can be added by having an RxJS interval
timer (for example) simply call refresh
on that channel at times.
You can do the “forget about updates that don’t actually change anything” logic either in the channel itself, or by hanging a pipe(distinctUntilChanged())
off of whereever you subscribe to its feed$
.