From 967296a5a2200e931cee2f21ef42e72c17a354fb Mon Sep 17 00:00:00 2001 From: Kurt Preston Date: Wed, 23 Jun 2021 11:49:49 -0500 Subject: [PATCH] Implementing unsubscription queue for transactional removes --- src/strongbus.ts | 34 +++++++++++++++++++++++++++++++--- src/strongbus_spec.ts | 2 +- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/strongbus.ts b/src/strongbus.ts index 94697b8..057329e 100644 --- a/src/strongbus.ts +++ b/src/strongbus.ts @@ -66,6 +66,14 @@ export class Bus implements Scannable|Events.WILDCARD, Set>(); private readonly lifecycle = new Map>(); + // Queue of unsubscription requests so that they are processed transactionally in oprder + private readonly _unsubQueue: { + token: string; + event: EventKeys|Events.WILDCARD; + handler: EventHandlers.GenericHandler; + }[] = []; + private _purgingUnsubQueue: boolean = false; + constructor(options?: Options) { this.options = { ...Bus.defaultOptions, @@ -426,13 +434,33 @@ export class Bus implements Scannable|Events.WILDCARD, handler: EventHandlers.GenericHandler): Events.Subscription { const token = randomId(); const sub = generateSubscription(() => { + this._unsubQueue.push({ + token, + event, + handler + }); + this.purgeUnsubQueue(); + }); + this.subscriptionCache.set(token, sub); + return sub; + } + + private purgeUnsubQueue() { + if(this._purgingUnsubQueue) { + return; + } else { + this._purgingUnsubQueue = true; + } + + while(this._unsubQueue.length) { + const {token, event, handler} = this._unsubQueue.shift(); if(this.subscriptionCache.has(token)) { this.subscriptionCache.delete(token); this.removeListener(event, handler); } - }); - this.subscriptionCache.set(token, sub); - return sub; + } + + this._purgingUnsubQueue = false; } private removeListener(event: EventKeys|Events.WILDCARD, handler: EventHandlers.GenericHandler): void { diff --git a/src/strongbus_spec.ts b/src/strongbus_spec.ts index 4d8a769..df88916 100644 --- a/src/strongbus_spec.ts +++ b/src/strongbus_spec.ts @@ -641,7 +641,7 @@ describe('Strongbus.Bus', () => { expect(onActive).toHaveBeenCalledTimes(1); }); - fit('handles unsubscribes fired from hooks', async () => { + it('handles unsubscribes fired from hooks', async () => { const sub1 = bus.on('foo', () => {}); const sub2 = bus.on('foo', () => {}); bus.hook('willRemoveListener', () => sub2());