Skip to content

Commit

Permalink
refactor(Subscription): minor size reduction (#5707)
Browse files Browse the repository at this point in the history
- Reduces the size of `Subscription` slightly.
- Moves back to a single property for single parent, many parents, scenarios
- Updates the type of `Teardown` to not be so loose. `Function` shouldn't be used.
  • Loading branch information
benlesh authored Sep 10, 2020
1 parent 09c5605 commit 6416935
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 55 deletions.
2 changes: 1 addition & 1 deletion api_guard/dist/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ export interface SubscriptionLike extends Unsubscribable {

export declare type Tail<X extends any[]> = ((...args: X) => any) extends ((arg: any, ...rest: infer U) => any) ? U : never;

export declare type TeardownLogic = Subscription | Unsubscribable | Function | void;
export declare type TeardownLogic = Subscription | Unsubscribable | (() => void) | void;

export declare function throwError(errorFactory: () => any): Observable<never>;
export declare function throwError(error: any): Observable<never>;
Expand Down
83 changes: 30 additions & 53 deletions src/internal/Subscription.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @prettier */
import { isFunction } from './util/isFunction';
import { UnsubscriptionError } from './util/UnsubscriptionError';
import { SubscriptionLike, TeardownLogic } from './types';
import { SubscriptionLike, TeardownLogic, Unsubscribable } from './types';

/**
* Represents a disposable resource, such as the execution of an Observable. A
Expand All @@ -27,11 +27,7 @@ export class Subscription implements SubscriptionLike {
*/
public closed = false;

/** If this subscription has been added to one parent, it will show up here */
private _singleParent: Subscription | null = null;

/** If this subscription has been added to more than one parent, they will show up here. */
private _parents: Subscription[] | null = null;
private _parentage: Subscription[] | Subscription | null = null;

/**
* The list of registered teardowns to execute upon unsubscription. Adding and removing from this
Expand All @@ -58,17 +54,13 @@ export class Subscription implements SubscriptionLike {
this.closed = true;

// Remove this from it's parents.

const { _singleParent } = this;
let _parents: Subscription[] | null;
if (_singleParent) {
this._singleParent = null;
_singleParent.remove(this);
} else if ((_parents = this._parents)) {
this._parents = null;
for (const parent of _parents) {
const { _parentage } = this;
if (Array.isArray(_parentage)) {
for (const parent of _parentage) {
parent.remove(this);
}
} else {
_parentage?.remove(this);
}

const { initialTeardown } = this;
Expand All @@ -81,15 +73,11 @@ export class Subscription implements SubscriptionLike {
}

const { _teardowns } = this;
this._teardowns = null;
if (_teardowns) {
this._teardowns = null;
for (const teardown of _teardowns) {
try {
if (typeof teardown === 'function') {
teardown();
} else {
teardown.unsubscribe();
}
execTeardown(teardown);
} catch (err) {
errors = errors ?? [];
if (err instanceof UnsubscriptionError) {
Expand Down Expand Up @@ -132,11 +120,7 @@ export class Subscription implements SubscriptionLike {
if (this.closed) {
// If this subscription is already closed,
// execute whatever teardown is handed to it automatically.
if (typeof teardown === 'function') {
teardown();
} else {
teardown.unsubscribe();
}
execTeardown(teardown);
} else {
if (teardown instanceof Subscription) {
// We don't add closed subscriptions, and we don't add the same subscription
Expand All @@ -146,8 +130,7 @@ export class Subscription implements SubscriptionLike {
}
teardown._addParent(this);
}
this._teardowns = this._teardowns ?? [];
this._teardowns.push(teardown);
(this._teardowns = this._teardowns ?? []).push(teardown);
}
}
}
Expand All @@ -158,7 +141,8 @@ export class Subscription implements SubscriptionLike {
* @param parent the parent to check for
*/
private _hasParent(parent: Subscription) {
return this._singleParent === parent || this._parents?.includes(parent) || false;
const { _parentage } = this;
return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));
}

/**
Expand All @@ -169,37 +153,22 @@ export class Subscription implements SubscriptionLike {
* @param parent The parent subscription to add
*/
private _addParent(parent: Subscription) {
const { _singleParent } = this;
let _parents: Subscription[] | null;
if (_singleParent) {
// We already have one parent so we'll need to expand
// to use an array
this._parents = [_singleParent, parent];
this._singleParent = null;
} else if ((_parents = this._parents)) {
// We already have more than one parent, so just add on to that array.
_parents.push(parent);
} else {
// This is our first parent.
this._singleParent = parent;
}
const { _parentage } = this;
this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;
}

/**
* Called on a child when it is removed via {@link remove}.
* @param parent The parent to remove
*/
private _removeParent(parent: Subscription) {
const { _singleParent } = this;
let _parents: Subscription[] | null;
if (_singleParent) {
if (_singleParent === parent) {
this._singleParent = null;
}
} else if ((_parents = this._parents)) {
const index = _parents.indexOf(parent);
if (index >= 0) {
_parents.splice(index, 1);
const { _parentage } = this;
if (_parentage === parent) {
this._parentage = null;
} else if (Array.isArray(_parentage)) {
const index = _parentage.indexOf(parent);
if (0 <= index) {
_parentage.splice(index, 1);
}
}
}
Expand Down Expand Up @@ -243,3 +212,11 @@ export function isSubscription(value: any): value is Subscription {
typeof value.unsubscribe === 'function')
);
}

function execTeardown(teardown: Unsubscribable | (() => void)) {
if (typeof teardown === 'function') {
teardown();
} else {
teardown.unsubscribe();
}
}
2 changes: 1 addition & 1 deletion src/internal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export interface Unsubscribable {
unsubscribe(): void;
}

export type TeardownLogic = Subscription | Unsubscribable | Function | void;
export type TeardownLogic = Subscription | Unsubscribable | (() => void) | void;

export interface SubscriptionLike extends Unsubscribable {
unsubscribe(): void;
Expand Down

0 comments on commit 6416935

Please sign in to comment.