Skip to content

Commit

Permalink
perf: ensure same hidden class for op subscribers
Browse files Browse the repository at this point in the history
  • Loading branch information
cartant committed Nov 6, 2020
1 parent 5c9b764 commit a2f7528
Showing 1 changed file with 28 additions and 9 deletions.
37 changes: 28 additions & 9 deletions src/internal/operators/OperatorSubscriber.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
/** @prettier */
import { Subscriber } from '../Subscriber';
import { noop } from '../util/noop';

// Ignore TypeScript's errors about the following methods being protected.
// They're stored here to avoid their needing to be looked up in the
// constructor.
// @ts-ignore
const defaultOnNext = Subscriber.prototype._next;
// @ts-ignore
const defaultOnError = Subscriber.prototype._error;
// @ts-ignore
const defaultOnComplete = Subscriber.prototype._complete;

/**
* A generic helper for allowing operators to be created with a Subscriber and
Expand All @@ -20,13 +31,21 @@ export class OperatorSubscriber<T> extends Subscriber<T> {
*/
constructor(
destination: Subscriber<any>,
onNext?: (value: T) => void,
onError?: (err: any) => void,
onComplete?: () => void,
private onUnsubscribe?: () => void
onNext: (value: T) => void = defaultOnNext,
onError: (err: any) => void = defaultOnError,
onComplete: () => void = defaultOnComplete,
private onUnsubscribe: () => void = noop
) {
// It's important - for performance reasons - that all of this class's
// members are initialized and that they are always initialized in the same
// order. This will ensure that all OperatorSubscriber instances have the
// same hidden class in V8. This, in turn, will help keep the number of
// hidden classes involved in property accesses within the base class as
// low as possible. If the number of hidden classes involved exceeds four,
// the property accesses will become megamorphic and performance penalties
// will be incurred - i.e. inline caches won't be used.
super(destination);
if (onNext) {
if (onNext !== defaultOnNext) {
this._next = function (value: T) {
try {
onNext(value);
Expand All @@ -35,8 +54,8 @@ export class OperatorSubscriber<T> extends Subscriber<T> {
}
};
}
if (onError) {
this._error = function (err) {
if (onError !== defaultOnError) {
this._error = function (err: any) {
try {
onError(err);
} catch (err) {
Expand All @@ -47,7 +66,7 @@ export class OperatorSubscriber<T> extends Subscriber<T> {
this.unsubscribe();
};
}
if (onComplete) {
if (onComplete !== defaultOnComplete) {
this._complete = function () {
try {
onComplete();
Expand All @@ -63,7 +82,7 @@ export class OperatorSubscriber<T> extends Subscriber<T> {

unsubscribe() {
// Execute additional teardown if we have any and we didn't already do so.
!this.closed && this.onUnsubscribe?.();
!this.closed && this.onUnsubscribe();
super.unsubscribe();
}
}

0 comments on commit a2f7528

Please sign in to comment.