From 4026b954a6d1dd06d530a1342365cce7de628aae Mon Sep 17 00:00:00 2001 From: ludvigalden Date: Mon, 10 Jan 2022 15:00:10 +0100 Subject: [PATCH] async notifier --- src/notifier-async.ts | 49 +++++++++++++++++++++++++++++++++++++++++++ src/types.ts | 4 ++++ 2 files changed, 53 insertions(+) create mode 100644 src/notifier-async.ts diff --git a/src/notifier-async.ts b/src/notifier-async.ts new file mode 100644 index 0000000..beacc99 --- /dev/null +++ b/src/notifier-async.ts @@ -0,0 +1,49 @@ +import { AsyncChangeListener, UnsubscribeFn } from "./types"; + +export class NotifierAsync extends Set> { + subscribe(listener: AsyncChangeListener): UnsubscribeFn { + this.add(listener); + + return () => this.unsubscribe(listener); + } + + unsubscribe(listener: AsyncChangeListener) { + this.delete(listener); + } + + notify(value: T): void | Promise; + notify(value: T, ...otherArgs: any[]): void | Promise; + notify(...args: any[]): void | Promise { + const promises: Promise[] = []; + Array.from(this.values()).forEach((listener) => { + const promiseOrVoid = listener(...(args as [T])); + if (isPromise(promiseOrVoid)) { + promises.push(promiseOrVoid); + } + }); + if (promises.length) { + return Promise.all(promises).then(() => {}); + } + } + + static get(abon: any): NotifierAsync { + return (abon as any)[KEY]; + } + + static define(abon: T): T { + Object.defineProperty(abon, KEY, { + value: new NotifierAsync(), + configurable: false, + writable: false, + enumerable: false, + }); + + return abon; + } +} + +const KEY = "__notifier"; + +function isPromise(v: any): v is Promise { + return Boolean(v && typeof v["then"] === "function"); +} diff --git a/src/types.ts b/src/types.ts index b1759bf..e8e6b4e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -38,3 +38,7 @@ export type SubscriberFlexResult = UnsubscribeFn | boolean | undefined | null | export type ComposedSubscriberFlexResult = SubscriberFlexResult | Iterable; export type ComposedSubscriberFlex = (listener: () => void) => ComposedSubscriberFlexResult; + +export interface AsyncChangeListener { + (current: T): void | Promise; +}