Skip to content

Commit

Permalink
perf(distinct): increase distinct() perf by improving deopts
Browse files Browse the repository at this point in the history
- moves keySelector call to a different function with a try catch to improve V8 optimization
- distinct calls with no keySelector passed now take a fully optimized path, doubling speed again

related #2009
  • Loading branch information
benlesh committed Oct 18, 2016
1 parent 74f012c commit df40ca5
Showing 1 changed file with 19 additions and 14 deletions.
33 changes: 19 additions & 14 deletions src/operator/distinct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { ISet, Set } from '../util/Set';
* @owner Observable
*/
export function distinct<T, K>(this: Observable<T>,
keySelector: (value: T) => K,
keySelector?: (value: T) => K,
flushes?: Observable<any>): Observable<T> {
return this.lift(new DistinctOperator(keySelector, flushes));
}
Expand All @@ -43,13 +43,9 @@ class DistinctOperator<T, K> implements Operator<T, T> {
export class DistinctSubscriber<T, K> extends OuterSubscriber<T, T> {
private values: ISet<K> = new Set<K>();

constructor(destination: Subscriber<T>, keySelector: (value: T) => K, flushes: Observable<any>) {
constructor(destination: Subscriber<T>, private keySelector: (value: T) => K, flushes: Observable<any>) {
super(destination);

if (typeof keySelector === 'function') {
this.keySelector = keySelector;
}

if (flushes) {
this.add(subscribeToResult(this, flushes));
}
Expand All @@ -66,22 +62,31 @@ export class DistinctSubscriber<T, K> extends OuterSubscriber<T, T> {
}

protected _next(value: T): void {
const { values, destination } = this;
if (this.keySelector) {
this._useKeySelector(value);
} else {
this._finalizeNext(value, value);
}
}

private _useKeySelector(value: T): void {
let key: K;
const { destination } = this;
try {
key = this.keySelector(value);
} catch (err) {
destination.error(err);
return;
}
if (values.has(key)) {
return;
}
values.add(key);
destination.next(value);
this._finalizeNext(key, value);
}

private keySelector(value: T|K): K {
return <K>value;
private _finalizeNext(key: K|T, value: T) {
const { values } = this;
if (!values.has(<K>key)) {
values.add(<K>key);
this.destination.next(value);
}
}

}

0 comments on commit df40ca5

Please sign in to comment.