From 8aee7ffc9cf13eda1ac8544e6536be4b98fc5bd2 Mon Sep 17 00:00:00 2001 From: Ben Lesh Date: Sun, 20 Feb 2022 13:29:59 -0600 Subject: [PATCH] perf: Don't clone observers unless you have to --- src/internal/Subject.ts | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/internal/Subject.ts b/src/internal/Subject.ts index 11ffb11dcb..fc4a7f021f 100644 --- a/src/internal/Subject.ts +++ b/src/internal/Subject.ts @@ -16,6 +16,9 @@ import { errorContext } from './util/errorContext'; */ export class Subject extends Observable implements SubscriptionLike { closed = false; + + private currentObservers: Observer[] | null = null; + /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */ observers: Observer[] = []; /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */ @@ -58,8 +61,10 @@ export class Subject extends Observable implements SubscriptionLike { errorContext(() => { this._throwIfClosed(); if (!this.isStopped) { - const copy = this.observers.slice(); - for (const observer of copy) { + if (!this.currentObservers) { + this.currentObservers = Array.from(this.observers); + } + for (const observer of this.currentObservers) { observer.next(value); } } @@ -95,7 +100,7 @@ export class Subject extends Observable implements SubscriptionLike { unsubscribe() { this.isStopped = this.closed = true; - this.observers = null!; + this.observers = this.currentObservers = null!; } get observed() { @@ -118,9 +123,15 @@ export class Subject extends Observable implements SubscriptionLike { /** @internal */ protected _innerSubscribe(subscriber: Subscriber) { const { hasError, isStopped, observers } = this; - return hasError || isStopped - ? EMPTY_SUBSCRIPTION - : (observers.push(subscriber), new Subscription(() => arrRemove(observers, subscriber))); + if (hasError || isStopped) { + return EMPTY_SUBSCRIPTION; + } + this.currentObservers = null; + observers.push(subscriber); + return new Subscription(() => { + this.currentObservers = null; + arrRemove(observers, subscriber); + }); } /** @internal */