Skip to content
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

refactor(Subscription): minor size reduction #5707

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -560,7 +560,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