-
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
fix(throttleTime): leading and trailing true should only emit a single value per time frame #2749
Conversation
Generated by 🚫 dangerJS |
I've been testing this, and the only hiccup is that the throttle call should come before the I suggest changing let emit = false;
if (!this.throttled && this.leading) {
emit = true;
} else ...
if (!this.throttled) this.throttle();
if (emit) this.destination.next(value); And also if (this.trailing && this._hasTrailingValue) {
let value = this._trailingValue;
this._trailingValue = null;
this._hasTrailingValue = false;
this.throttle();
this.destination.next(value);
} I have also recommended that this PR be replicated to solve #2466 but considering what I have discovered regarding the timing this may not be so simple. |
How did you test the hiccup? if (!this.throttled && this.leading) {
this.destination.next(value);
} /* ... |
Later in the same function is the call to |
Thanks, now I understood the issue. |
…e value per time frame
74faac5
to
9cda512
Compare
rebased & added your feedback |
bc1b6cc
to
e0953f1
Compare
e0953f1
to
9fc78aa
Compare
} | ||
|
||
if (!this.throttled) { | ||
this.throttle(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we refactor this a little to be:
if (!this.trottled) {
this.throttle();
if (this.leading) {
this.destination.next(value);
}
}
if (this.trailing) {
this._trailingValue = value;
this._hasTrailingValue = true;
}
I'm not sure in it's current configuration it will work as desired, because of that else if
. If it's trailing, we always want to record the value, not only if we've already started throttling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then throttleTime
would emit the same input twice on {leading:true, trailing: true}
. I guess in the end it doesn't matter when throttleTime is used in conjunction with distinctUntilChanged
, but it feels wrong regardless.
Observable.of(1).throttleTime(100, {leading:true, trailing: true}).subscribe((n) => console.log(n));
// 1
// 1
vs. lodash
fn = _.throttle((n) => console.log(n), 100, {leading:true, trailing: true});
fn(1);
// 1
this._trailingValue = null; | ||
this._hasTrailingValue = false; | ||
this.throttle(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is unnecessary and changes the behavior of the operator. It's not supposed to start throttling again when the throttle is cleared.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm.. I think there's a disconnect here. throttle()
actually starts the throttle measurement. The, with leading
and trailing
both true
, it should emit the same as it would with leading
behavior, but then emit the trailing value at the end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I okay, I actually see what you're saying now. This is to start the throttle again as soon as there's another emission (due to trailing behavior)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay... the more I look at this, the more I think it will have to be a change that lands in v 6.0, because it will be a breaking change for someone. (Albeit a fix)
src/operators/throttleTime.ts
Outdated
if (throttled) { | ||
throttled.unsubscribe(); | ||
this.remove(throttled); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is unnecessary, the unsubscribe()
will remove the inner subscription.
spec/operators/throttleTime-spec.ts
Outdated
|
||
expectObservable(e1.throttleTime(50, rxTestScheduler)).toBe(expected); | ||
expectObservable(e1.throttleTime(50, rxTestScheduler, {leading: true, trailing: false})).toBe(expected); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you could use the time
function here and represent the time
as marbles above like:
const t1 = '----|';
and then use time(t1)
which returns a number.
That would be ideal as the test could be more readable, you can even used commented out ----|
marblse to demonstrate where the throttles occur.
Remember, the whole purpose of these tests is to be more readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do the same for the other tests.
2b67db9
to
1b6c92a
Compare
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. |
Fixes #2727
fix 1:
throttleTime
{leading: true, trailing: true}
Currently it behaves like
By not scheduling a new throttle when emitting a trailing value.
this PR changes it to:
fix 2:
throttleTime
{leading: false, trailing: true}
Currently it behaves like
First and only value in each timeframe is dropped by not storing the first value when not yet throttled. So this code doesn't console.log anything:
This PR changes the behavior to:
I added tests to cover those issues.