-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cache()
behaves unexpectedly with non-terminating sources
#1959
Comments
Looks like the issue is that when Doesn't seem like a hard fix... just requires a little thought. |
In fact, I think it requires thought to figure out if this is a bug, or just counter-intuitive behavior. |
Thinking about it, it seems like this isn't a bug, so much as it is counter-intuitive behavior. consider: const source = Observable.interval(1000).cache(1) That part alone is a really strange use of In the above case we're saying If you use QuestionsDo we want a "refCounting" behavior with |
If we can't reach consensus quickly, we might consider removing the operator entirely for v5.0 and try to get it (or something like it) into v5.1+ or some kitchen sink library. The cache operator appears to have a history of confusion #839 #1541 #1940 #1765 which isn't surprising because an operator named "cache" is pretty ambiguous since there are so many strategies. |
@Blesh—right on abut the counter-intuitive behavior. My expectation is that the refCount going back to 0 when the source hasn't yet completed would still keep the subscription to the source until it actually terminates, and only then unsubscribes and get into the mode of returning cached behavior. In my repro case, for instance, if I don't have the setTimeout in the last line, or it doesn't wait until the take() unsubscribes, then that 2nd subscribe never terminates. While I used a never ending sequence, it doesn't have to be one, just one that terminates after |
I honestly think the Here's an example of what I mean: import { Observable, ReplaySubject } from 'rxjs';
Observable.prototype.cache = function cache(
keySelector,
project,
evictionSelector = () => Observable.never(),
map = {}) {
return this.groupBy(
keySelector,
(element) => element,
(elements) => evictionSelector(elements)
.ignoreElements()
.finally(() => {
console.log(`forgetting ${elements.key}`);
delete map[elements.key];
})
)
.mergeMap((elements) =>
map[elements.key] || (
map[elements.key] = project(elements)));
}
const cached = Observable
.interval(100)
.cache(
(value) => value,
(values) => {
return values
.multicast(new ReplaySubject())
.refCount()
}
);
console.log('first subscribed');
cached
.take(20)
.subscribe(
(i) => console.log(`first subscriber: ${i}`),
(e) => console.error(e),
( ) => console.log('first complete')
);
setTimeout(() => {
console.log('second subscribed');
cached
.take(20)
.subscribe(
(i) => console.log(`second subscriber: ${i}`),
(e) => console.error(e),
( ) => console.log('second complete')
);
}, 1000); |
At this point, I'm in favor of pulling the The goal was to provide an operator that could be used with AJAX use-cases that gave a simplistic caching behavior, similar to what one might find with promises, but providing the ability to abort the request, and the ability to retry the request. Any other use case that might fall under "caching" wasn't really in this operator's design, however I can understand the confusion. Alternatively, we could rename it to something like |
cache no longer exists. LOL. |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
RxJS version: v5.0.0-beta.12
Code to reproduce:
Expected behavior:
Never ending console logs.
Actual behavior:
Single console log.
Additional information:
It's surprising behavior and undocumented (unless you read the code.) It definitely bit me and I'd consider it a bug.
The text was updated successfully, but these errors were encountered: