From 08f357d5694800e7359ab64fbcdf16366dd70922 Mon Sep 17 00:00:00 2001 From: Adam Smith Date: Sat, 14 Dec 2024 12:54:27 +0300 Subject: [PATCH] feat: added a signal for unsubscribing on abort --- src/index.ts | 30 +++++++++++++++++++++++++++--- test/index_test.ts | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 17672aa..ef08b73 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,11 +20,23 @@ export type EventHandlerMap> = Map< EventHandlerList | WildCardEventHandlerList >; +export type SubscribeParams = { + signal: AbortSignal +} + export interface Emitter> { all: EventHandlerMap; - on(type: Key, handler: Handler): void; - on(type: '*', handler: WildcardHandler): void; + on( + type: Key, + handler: Handler, + params?: Partial + ): void; + on( + type: '*', + handler: WildcardHandler, + params?: Partial + ): void; off( type: Key, @@ -63,13 +75,25 @@ export default function mitt>( * @param {Function} handler Function to call in response to given event * @memberOf mitt */ - on(type: Key, handler: GenericEventHandler) { + on( + type: Key, + handler: GenericEventHandler, + params?: Partial, + ) { + if (params?.signal?.aborted) { + return; + } + const handlers: Array | undefined = all!.get(type); if (handlers) { handlers.push(handler); } else { all!.set(type, [handler] as EventHandlerList); } + + params?.signal?.addEventListener('abort', () => { + this.off(type, handler as Handler); + }); }, /** diff --git a/test/index_test.ts b/test/index_test.ts index 31c9495..4ea4a52 100644 --- a/test/index_test.ts +++ b/test/index_test.ts @@ -103,6 +103,43 @@ describe('mitt#', () => { inst.on('foo', foo); expect(events.get('foo')).to.deep.equal([foo, foo]); }); + + it('should unsubscribe when signal aborted', () => { + const foo = spy(); + const abortController = new AbortController(); + + inst.on( + 'foo', + foo, + { signal: abortController.signal } + ); + inst.emit('foo'); + + abortController.abort(); + + inst.emit('foo'); + + expect(foo).to.have.been.callCount(1); + }); + + it('should make multiple unsubscribe when aborted', () => { + const foo = spy(); + const bar = spy(); + const abortController = new AbortController(); + + inst.on('foo', foo, { signal: abortController.signal }); + inst.on('bar', bar, { signal: abortController.signal }); + inst.emit('foo'); + inst.emit('bar'); + + abortController.abort(); + + inst.emit('foo'); + inst.emit('bar'); + + expect(foo).to.have.been.callCount(1); + expect(bar).to.have.been.callCount(1); + }); }); describe('off()', () => {